diff --git a/frameworks/js/napi/BUILD.gn b/frameworks/js/napi/BUILD.gn index e424a4642fa0a6c82d472ceaab4f142c79fe5d1a..c6a63ce64717403c7f0670cadca07f34d8ca340c 100644 --- a/frameworks/js/napi/BUILD.gn +++ b/frameworks/js/napi/BUILD.gn @@ -77,6 +77,8 @@ group("napi_packages") { "${ability_runtime_napi_path}/js_dialog_request:dialogrequest_napi", "${ability_runtime_napi_path}/js_dialog_session:dialogsession_napi", "${ability_runtime_napi_path}/js_mission_manager:missionmanager", + "${ability_runtime_napi_path}/live_form_extension_ability:liveformextensionability_napi", + "${ability_runtime_napi_path}/live_form_extension_context:liveformextensioncontext_napi", "${ability_runtime_napi_path}/mission_manager:distributedmissionmanager", "${ability_runtime_napi_path}/mission_manager:missionmanager_napi", "${ability_runtime_napi_path}/particleAbility:particleability", diff --git a/frameworks/js/napi/live_form_extension_ability/BUILD.gn b/frameworks/js/napi/live_form_extension_ability/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e5ffdeadf8e4b9bcb8ad234d3f302d7f6251016c --- /dev/null +++ b/frameworks/js/napi/live_form_extension_ability/BUILD.gn @@ -0,0 +1,50 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + +import("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni") +import("//build/ohos.gni") + +es2abc_gen_abc("gen_live_form_extension_ability_abc") { + src_js = rebase_path("live_form_extension_ability.js") + dst_file = rebase_path(target_out_dir + "/live_form_extension_ability.abc") + in_puts = [ "live_form_extension_ability.js" ] + out_puts = [ target_out_dir + "/live_form_extension_ability.abc" ] + extra_args = [ "--module" ] +} + +gen_js_obj("live_form_extension_ability_js") { + input = "live_form_extension_ability.js" + output = target_out_dir + "/live_form_extension_ability.o" +} + +gen_js_obj("live_form_extension_ability_abc") { + input = get_label_info(":gen_live_form_extension_ability_abc", + "target_out_dir") + "/live_form_extension_ability.abc" + output = target_out_dir + "/live_form_extension_ability_abc.o" + dep = ":gen_live_form_extension_ability_abc" +} + +ohos_shared_library("liveformextensionability_napi") { + sources = [ "live_form_extension_ability_module.cpp" ] + + deps = [ + ":live_form_extension_ability_abc", + ":live_form_extension_ability_js", + ] + + external_deps = [ "napi:ace_napi" ] + + relative_install_dir = "module/app/ability" + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/js/napi/live_form_extension_ability/live_form_extension_ability.js b/frameworks/js/napi/live_form_extension_ability/live_form_extension_ability.js new file mode 100644 index 0000000000000000000000000000000000000000..2ef197e90fba2c849a6458183efdbc953a1e3284 --- /dev/null +++ b/frameworks/js/napi/live_form_extension_ability/live_form_extension_ability.js @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +let UIExtensionAbility = requireNapi('app.ability.UIExtensionAbility'); + +export default class LiveFormExtensionAbility extends UIExtensionAbility {} \ No newline at end of file diff --git a/frameworks/js/napi/live_form_extension_ability/live_form_extension_ability_module.cpp b/frameworks/js/napi/live_form_extension_ability/live_form_extension_ability_module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b087ca49e767a750b22a66976e2fd380b046460 --- /dev/null +++ b/frameworks/js/napi/live_form_extension_ability/live_form_extension_ability_module.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "native_engine/native_engine.h" + +extern const char _binary_live_form_extension_ability_js_start[]; +extern const char _binary_live_form_extension_ability_js_end[]; +extern const char _binary_live_form_extension_ability_abc_start[]; +extern const char _binary_live_form_extension_ability_abc_end[]; + +static napi_module _module = { + .nm_version = 0, + .nm_filename = "app/ability/libliveformextensionability_napi.so/live_form_extension_ability.js", + .nm_modname = "app.ability.LiveFormExtensionAbility", +}; +extern "C" __attribute__((constructor)) void NAPI_app_ability_LiveFormExtensionAbility_AutoRegister() +{ + napi_module_register(&_module); +} + +extern "C" __attribute__((visibility("default"))) void NAPI_app_ability_LiveFormExtensionAbility_GetJSCode( + const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_live_form_extension_ability_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_live_form_extension_ability_js_end - _binary_live_form_extension_ability_js_start; + } +} + +extern "C" __attribute__((visibility("default"))) void NAPI_app_ability_LiveFormExtensionAbility_GetABCCode( + const char **buf, int *buflen) +{ + if (buf != nullptr) { + *buf = _binary_live_form_extension_ability_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_live_form_extension_ability_abc_end - _binary_live_form_extension_ability_abc_start; + } +} \ No newline at end of file diff --git a/frameworks/js/napi/live_form_extension_context/BUILD.gn b/frameworks/js/napi/live_form_extension_context/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..84d8ef945c901f9cc2f1b435493acb587fcdfb0d --- /dev/null +++ b/frameworks/js/napi/live_form_extension_context/BUILD.gn @@ -0,0 +1,50 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + +import("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni") +import("//build/ohos.gni") + +es2abc_gen_abc("gen_live_form_extension_context_abc") { + src_js = rebase_path("live_form_extension_context.js") + dst_file = rebase_path(target_out_dir + "/live_form_extension_context.abc") + in_puts = [ "live_form_extension_context.js" ] + out_puts = [ target_out_dir + "/live_form_extension_context.abc" ] + extra_args = [ "--module" ] +} + +gen_js_obj("live_form_extension_context_js") { + input = "live_form_extension_context.js" + output = target_out_dir + "/live_form_extension_context.o" +} + +gen_js_obj("live_form_extension_context_abc") { + input = get_label_info(":gen_live_form_extension_context_abc", + "target_out_dir") + "/live_form_extension_context.abc" + output = target_out_dir + "/live_form_extension_context_abc.o" + dep = ":gen_live_form_extension_context_abc" +} + +ohos_shared_library("liveformextensioncontext_napi") { + sources = [ "live_form_extension_context_module.cpp" ] + + deps = [ + ":live_form_extension_context_abc", + ":live_form_extension_context_js", + ] + + external_deps = [ "napi:ace_napi" ] + + relative_install_dir = "module/application" + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/js/napi/live_form_extension_context/live_form_extension_context.js b/frameworks/js/napi/live_form_extension_context/live_form_extension_context.js new file mode 100644 index 0000000000000000000000000000000000000000..aafbb9516fc431928115f9ec9c2eb2a32e07d720 --- /dev/null +++ b/frameworks/js/napi/live_form_extension_context/live_form_extension_context.js @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +let ExtensionContext = requireNapi('application.ExtensionContext'); + +class LiveFormExtensionContext extends ExtensionContext { + constructor(obj) { + super(obj); + } +} + +export default LiveFormExtensionContext; \ No newline at end of file diff --git a/frameworks/js/napi/live_form_extension_context/live_form_extension_context_module.cpp b/frameworks/js/napi/live_form_extension_context/live_form_extension_context_module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38691d097cccab6626b5e544784b882d167e92c6 --- /dev/null +++ b/frameworks/js/napi/live_form_extension_context/live_form_extension_context_module.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "native_engine/native_engine.h" + +extern const char _binary_live_form_extension_context_js_start[]; +extern const char _binary_live_form_extension_context_js_end[]; +extern const char _binary_live_form_extension_context_abc_start[]; +extern const char _binary_live_form_extension_context_abc_end[]; + +static napi_module _module = { + .nm_version = 0, + .nm_filename = "application/liveformextensioncontext_napi.so/live_form_extension_context.js", + .nm_modname = "application.LiveFormExtensionContext", +}; + +extern "C" __attribute__((constructor)) void NAPI_application_LiveFormExtensionContext_AutoRegister() +{ + napi_module_register(&_module); +} + +extern "C" __attribute__((visibility("default"))) void NAPI_application_LiveFormExtensionContext_GetJSCode( + const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_live_form_extension_context_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_live_form_extension_context_js_end - _binary_live_form_extension_context_js_start; + } +} + +extern "C" __attribute__((visibility("default"))) void NAPI_application_LiveFormExtensionContext_GetABCCode( + const char **buf, int *buflen) +{ + if (buf != nullptr) { + *buf = _binary_live_form_extension_context_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_live_form_extension_context_abc_end - _binary_live_form_extension_context_abc_start; + } +} \ No newline at end of file diff --git a/frameworks/native/ability/native/BUILD.gn b/frameworks/native/ability/native/BUILD.gn index e48187c2ab2086eb467828ff8575a213beae56d0..f29454a3f33c97963191ad346de6bdffb14dd561 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -1265,6 +1265,7 @@ group("extension_module") { ":action_extension_module", ":auto_fill_extension_module", ":embedded_ui_extension_module", + ":live_form_extension_module", ":photo_editor_extension_module", ":service_extension_module", ":share_extension_module", @@ -1433,6 +1434,60 @@ ohos_shared_library("share_extension") { part_name = "ability_runtime" } +config("live_form_extension_config") { + visibility = [ ":*" ] + include_dirs = [ + "${ability_runtime_path}/interfaces/kits/native/ability/native/live_form_extension_ability", + "${ability_runtime_path}/interfaces/kits/native/ability/native/ability_runtime", + "${ability_runtime_path}/interfaces/kits/native/ability/native/ui_extension_ability", + "${ability_runtime_path}/interfaces/kits/native/ability/ability_runtime", + "${ability_runtime_path}/interfaces/kits/native/ability/native", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/context", + ] +} + +ohos_shared_library("live_form_extension") { + configs = [ ":live_form_extension_config" ] + + sources = [ + "${ability_runtime_native_path}/ability/native/live_form_extension_ability/js_live_form_extension.cpp", + "${ability_runtime_native_path}/ability/native/live_form_extension_ability/js_live_form_extension_context.cpp", + "${ability_runtime_native_path}/ability/native/live_form_extension_ability/live_form_extension.cpp", + "${ability_runtime_native_path}/ability/native/live_form_extension_ability/live_form_extension_context.cpp", + ] + + deps = [ + ":abilitykit_native", + ":ui_extension", + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_innerkits_path}/ability_manager:ability_start_options", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_napi_path}/inner/napi_common:napi_common", + "${ability_runtime_native_path}/ability:ability_context_native", + "${ability_runtime_native_path}/ability/native:ability_business_error", + "${ability_runtime_native_path}/appkit:app_context", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "c_utils:utils", + "eventhandler:libeventhandler", + "hilog:libhilog", + "hitrace:hitrace_meter", + "ipc:ipc_napi", + "napi:ace_napi", + ] + + if (ability_runtime_graphics) { + external_deps += [ "window_manager:libwm" ] + } + + subsystem_name = "ability" + part_name = "ability_runtime" +} + config("action_extension_config") { visibility = [ ":*" ] include_dirs = [ @@ -1518,6 +1573,37 @@ ohos_shared_library("share_extension_module") { part_name = "ability_runtime" } +ohos_shared_library("live_form_extension_module") { + sources = [ "${ability_runtime_native_path}/ability/native/live_form_extension_ability/live_form_extension_module_loader.cpp" ] + + configs = [ + ":ability_config", + ":live_form_extension_config", + ] + + deps = [ + ":live_form_extension", + "${ability_runtime_innerkits_path}/runtime:runtime", + ] + + external_deps = [ + "ability_base:configuration", + "ability_base:session_info", + "ability_base:want", + "bundle_framework:appexecfwk_core", + "hilog:libhilog", + "napi:ace_napi", + ] + + if (ability_runtime_graphics) { + external_deps += [ "window_manager:libwm" ] + } + + relative_install_dir = "extensionability/" + subsystem_name = "ability" + part_name = "ability_runtime" +} + ohos_shared_library("auto_startup_callback") { include_dirs = [ "${ability_runtime_path}/interfaces/kits/native/ability/native/ability_business_error" ] diff --git a/frameworks/native/ability/native/live_form_extension_ability/js_live_form_extension.cpp b/frameworks/native/ability/native/live_form_extension_ability/js_live_form_extension.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0d5fa84fd6f44f8ac89f5eaf182c044cabb6ce9 --- /dev/null +++ b/frameworks/native/ability/native/live_form_extension_ability/js_live_form_extension.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "js_live_form_extension.h" + +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "hitrace_meter.h" +#include "js_ui_extension_base.h" + +namespace OHOS { +namespace AbilityRuntime { +JsLiveFormExtension *JsLiveFormExtension::Create(const std::unique_ptr &runtime) +{ + return new JsLiveFormExtension(runtime); +} + +JsLiveFormExtension::JsLiveFormExtension(const std::unique_ptr &runtime) +{ + std::shared_ptr uiExtensionBaseImpl = std::make_shared(runtime); + SetUIExtensionBaseImpl(uiExtensionBaseImpl); +} + +JsLiveFormExtension::~JsLiveFormExtension() +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "destructor."); +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/ability/native/live_form_extension_ability/js_live_form_extension_context.cpp b/frameworks/native/ability/native/live_form_extension_ability/js_live_form_extension_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b38e36791bd7fb83e42e0a6303cd730bf27a0964 --- /dev/null +++ b/frameworks/native/ability/native/live_form_extension_ability/js_live_form_extension_context.cpp @@ -0,0 +1,960 @@ +/* + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "js_live_form_extension_context.h" + +#include + +#include "ability_manager_client.h" +#include "ability_manager_errors.h" +#include "event_handler.h" +#include "hilog_tag_wrapper.h" +#include "js_extension_context.h" +#include "js_error_utils.h" +#include "js_data_struct_converter.h" +#include "js_runtime.h" +#include "js_runtime_utils.h" +#include "napi/native_api.h" +#include "napi_common_ability.h" +#include "napi_common_want.h" +#include "napi_common_util.h" +#include "napi_common_start_options.h" +#include "napi_remote_object.h" +#include "open_link_options.h" +#include "open_link/napi_common_open_link_options.h" +#include "start_options.h" +#include "hitrace_meter.h" +#include "uri.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr int32_t INDEX_ZERO = 0; +constexpr int32_t INDEX_ONE = 1; +constexpr int32_t INDEX_TWO = 2; +constexpr size_t ARGC_ZERO = 0; +constexpr size_t ARGC_ONE = 1; +constexpr size_t ARGC_TWO = 2; + +const std::string ATOMIC_SERVICE_PREFIX = "com.atomicservice."; +constexpr size_t ARGC_THREE = 3; +} // namespace + +static std::map, key_compare> g_connects; +static int64_t g_serialNumber = 0; +void RemoveConnection(int64_t connectId) +{ + auto item = std::find_if(g_connects.begin(), g_connects.end(), + [&connectId](const auto &obj) { + return connectId == obj.first.id; + }); + if (item != g_connects.end()) { + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "remove conn ability exist"); + if (item->second) { + item->second->RemoveConnectionObject(); + } + g_connects.erase(item); + } else { + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "remove conn ability not exist"); + } +} + +void FindConnection(AAFwk::Want& want, sptr& connection, int64_t& connectId) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "Disconnect ability enter, connection:%{public}d.", + static_cast(connectId)); + auto item = std::find_if(g_connects.begin(), + g_connects.end(), + [&connectId](const auto &obj) { + return connectId == obj.first.id; + }); + if (item != g_connects.end()) { + // match id + want = item->first.want; + connection = item->second; + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "find conn ability exist"); + } + return; +} + +bool CheckConnectionParam(napi_env env, napi_value value, sptr& connection, + AAFwk::Want& want) +{ + if (!CheckTypeForNapiValue(env, value, napi_object)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "Failed to get connection object"); + return false; + } + connection->SetJsConnectionObject(value); + LiveFormExtensionConnectionKey key; + key.id = g_serialNumber; + key.want = want; + connection->SetConnectionId(key.id); + g_connects.emplace(key, connection); + if (g_serialNumber < INT32_MAX) { + g_serialNumber++; + } else { + g_serialNumber = 0; + } + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "not find connection, create a new connection"); + return true; +} + +void JsLiveFormExtensionContext::Finalizer(napi_env env, void* data, void* hint) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called"); + std::unique_ptr(static_cast(data)); +} + +napi_value JsLiveFormExtensionContext::StartAbility(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsLiveFormExtensionContext, OnStartAbility); +} + +napi_value JsLiveFormExtensionContext::OpenLink(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsLiveFormExtensionContext, OnOpenLink); +} + +napi_value JsLiveFormExtensionContext::StartAbilityForResult(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsLiveFormExtensionContext, OnStartAbilityForResult); +} + +napi_value JsLiveFormExtensionContext::StartAbilityForResultAsCaller(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsLiveFormExtensionContext, OnStartAbilityForResultAsCaller); +} + +napi_value JsLiveFormExtensionContext::ConnectAbility(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsLiveFormExtensionContext, OnConnectAbility); +} + +napi_value JsLiveFormExtensionContext::DisconnectAbility(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsLiveFormExtensionContext, OnDisconnectAbility); +} + +napi_value JsLiveFormExtensionContext::ReportDrawnCompleted(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsLiveFormExtensionContext, OnReportDrawnCompleted); +} + +napi_value JsLiveFormExtensionContext::OpenAtomicService(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsLiveFormExtensionContext, OnOpenAtomicService); +} + +napi_value JsLiveFormExtensionContext::OnStartAbility(napi_env env, NapiCallbackInfo& info) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called"); + if (info.argc < ARGC_ONE) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "invalid argc"); + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + + size_t unwrapArgc = 0; + AAFwk::Want want; + AAFwk::StartOptions startOptions; + if (!CheckStartAbilityInputParam(env, info, want, startOptions, unwrapArgc)) { + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "Failed, input param type invalid"); + ThrowInvalidParamError(env, "Parse param want failed, want must be Want"); + return CreateJsUndefined(env); + } + + NapiAsyncTask::CompleteCallback complete = + [weak = context_, want, startOptions, unwrapArgc](napi_env env, NapiAsyncTask& task, int32_t status) { + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "startAbility begin"); + auto context = weak.lock(); + if (!context) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "context is released"); + task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)); + return; + } + + ErrCode innerErrorCode = ERR_OK; + (unwrapArgc == 1) ? innerErrorCode = context->StartAbility(want) : + innerErrorCode = context->StartAbility(want, startOptions); + if (innerErrorCode == 0) { + task.Resolve(env, CreateJsUndefined(env)); + } else { + task.Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode)); + } + }; + + napi_value lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc]; + napi_value result = nullptr; + NapiAsyncTask::ScheduleHighQos("JSLiveFormExtensionContext OnStartAbility", + env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result)); + return result; +} + +static bool CheckUrl(std::string &urlValue) +{ + if (urlValue.empty()) { + return false; + } + Uri uri = Uri(urlValue); + if (uri.GetScheme().empty() || uri.GetHost().empty()) { + return false; + } + + return true; +} + +bool JsLiveFormExtensionContext::CreateOpenLinkTask(const napi_env &env, const napi_value &lastParam, + AAFwk::Want &want, int &requestCode) +{ + want.SetParam(Want::PARAM_RESV_FOR_RESULT, true); + napi_value result = nullptr; + std::unique_ptr uasyncTask = + CreateAsyncTaskWithLastParam(env, lastParam, nullptr, nullptr, &result); + std::shared_ptr asyncTask = std::move(uasyncTask); + RuntimeTask task = [env, asyncTask](int resultCode, const AAFwk::Want& want, bool isInner) { + TAG_LOGI(AAFwkTag::LIVE_FORM_EXT, "OnOpenLink async callback is begin"); + HandleScope handleScope(env); + napi_value abilityResult = AppExecFwk::WrapAbilityResult(env, resultCode, want); + if (abilityResult == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "wrap abilityResult error"); + asyncTask->Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER)); + return; + } + if (isInner) { + asyncTask->Reject(env, CreateJsErrorByNativeErr(env, resultCode)); + return; + } + asyncTask->ResolveWithNoError(env, abilityResult); + }; + auto context = context_.lock(); + if (context == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "context is released"); + return false; + } + requestCode = context->GenerateCurRequestCode(); + context->InsertResultCallbackTask(requestCode, std::move(task)); + return true; +} + +void JsLiveFormExtensionContext::RemoveOpenLinkTask(int requestCode) +{ + auto context = context_.lock(); + if (context == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "context is released"); + return; + } + context->RemoveResultCallbackTask(requestCode); +} + +static bool ParseOpenLinkParams(const napi_env &env, const NapiCallbackInfo &info, std::string &linkValue, + AAFwk::OpenLinkOptions &openLinkOptions, AAFwk::Want &want) +{ + if (info.argc != ARGC_THREE) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "wrong arguments num"); + return false; + } + + if (!CheckTypeForNapiValue(env, info.argv[ARGC_ZERO], napi_string)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "link must be string"); + return false; + } + if (!ConvertFromJsValue(env, info.argv[ARGC_ZERO], linkValue) || !CheckUrl(linkValue)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "link parameter invalid"); + return false; + } + + if (CheckTypeForNapiValue(env, info.argv[INDEX_ONE], napi_object)) { + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "OpenLinkOptions is used"); + if (!AppExecFwk::UnwrapOpenLinkOptions(env, info.argv[INDEX_ONE], openLinkOptions, want)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "openLinkOptions parse failed"); + return false; + } + } + + return true; +} + +napi_value JsLiveFormExtensionContext::OnOpenLink(napi_env env, NapiCallbackInfo& info) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "OnOpenLink"); + + std::string linkValue(""); + AAFwk::OpenLinkOptions openLinkOptions; + AAFwk::Want want; + want.SetParam(AppExecFwk::APP_LINKING_ONLY, false); + + if (!ParseOpenLinkParams(env, info, linkValue, openLinkOptions, want)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "parse openLink arguments failed"); + ThrowInvalidParamError(env, + "Parse param link or openLinkOptions failed, link must be string, openLinkOptions must be options."); + return CreateJsUndefined(env); + } + + want.SetUri(linkValue); + std::string startTime = std::to_string(std::chrono::duration_cast(std::chrono:: + system_clock::now().time_since_epoch()).count()); + want.SetParam(Want::PARAM_RESV_START_TIME, startTime); + + int requestCode = -1; + if (CheckTypeForNapiValue(env, info.argv[INDEX_TWO], napi_function)) { + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "completionHandler is used"); + CreateOpenLinkTask(env, info.argv[INDEX_TWO], want, requestCode); + } + return OnOpenLinkInner(env, want, requestCode, startTime, linkValue); +} + +napi_value JsLiveFormExtensionContext::OnOpenLinkInner(napi_env env, const AAFwk::Want& want, + int requestCode, const std::string& startTime, const std::string& url) +{ + auto innerErrorCode = std::make_shared(ERR_OK); + NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, innerErrorCode, requestCode]() { + auto context = weak.lock(); + if (!context) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "context is released"); + *innerErrorCode = static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT); + return; + } + *innerErrorCode = context->OpenLink(want, requestCode); + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrorCode, requestCode, startTime, url, this]( + napi_env env, NapiAsyncTask& task, int32_t status) { + if (*innerErrorCode == 0) { + TAG_LOGI(AAFwkTag::LIVE_FORM_EXT, "OpenLink succeeded"); + return; + } + if (freeInstallObserver_ == nullptr) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "freeInstallObserver_ is nullptr"); + RemoveOpenLinkTask(requestCode); + return; + } + if (*innerErrorCode == AAFwk::ERR_OPEN_LINK_START_ABILITY_DEFAULT_OK) { + TAG_LOGI(AAFwkTag::LIVE_FORM_EXT, "start ability by default succeeded"); + freeInstallObserver_->OnInstallFinishedByUrl(startTime, url, ERR_OK); + return; + } + TAG_LOGI(AAFwkTag::LIVE_FORM_EXT, "OpenLink failed"); + freeInstallObserver_->OnInstallFinishedByUrl(startTime, url, *innerErrorCode); + RemoveOpenLinkTask(requestCode); + }; + + napi_value result = nullptr; + AddFreeInstallObserver(env, want, nullptr, &result, false, true); + NapiAsyncTask::ScheduleHighQos("JsLiveFormExtensionContext::OnOpenLink", env, + CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), nullptr)); + + return result; +} + +napi_value JsLiveFormExtensionContext::OnStartAbilityForResult(napi_env env, NapiCallbackInfo& info) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called"); + if (info.argc == ARGC_ZERO) { + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + size_t unwrapArgc = 0; + AAFwk::Want want; + AAFwk::StartOptions startOptions; + if (!CheckStartAbilityInputParam(env, info, want, startOptions, unwrapArgc)) { + ThrowInvalidParamError(env, "Parse param want failed, want must be Want."); + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "input param type invalid"); + return CreateJsUndefined(env); + } + napi_value lastParam = info.argc > unwrapArgc ? info.argv[unwrapArgc] : nullptr; + napi_value result = nullptr; + std::unique_ptr uasyncTask = CreateAsyncTaskWithLastParam(env, lastParam, nullptr, nullptr, &result); + std::shared_ptr asyncTask = std::move(uasyncTask); + RuntimeTask task = [env, asyncTask](int resultCode, const AAFwk::Want &want, bool isInner) { + TAG_LOGI(AAFwkTag::LIVE_FORM_EXT, "called"); + napi_value abilityResult = AppExecFwk::WrapAbilityResult(env, resultCode, want); + if (abilityResult == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "wrap abilityResult failed"); + asyncTask->Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER)); + return; + } + if (isInner) { + asyncTask->Reject(env, CreateJsErrorByNativeErr(env, resultCode)); + return; + } + asyncTask->Resolve(env, abilityResult); + }; + auto context = context_.lock(); + if (context == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "context is released"); + asyncTask->Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)); + return result; + } + want.SetParam(Want::PARAM_RESV_FOR_RESULT, true); + int curRequestCode = context->GenerateCurRequestCode(); + (unwrapArgc == INDEX_ONE) ? context->StartAbilityForResult(want, curRequestCode, std::move(task)) + : context->StartAbilityForResult(want, startOptions, curRequestCode, std::move(task)); + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "OnStartAbilityForResult end"); + return result; +} + +napi_value JsLiveFormExtensionContext::OnStartAbilityForResultAsCaller(napi_env env, NapiCallbackInfo &info) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called"); + if (info.argc == ARGC_ZERO) { + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + size_t unwrapArgc = 0; + AAFwk::Want want; + AAFwk::StartOptions startOptions; + if (!CheckStartAbilityInputParam(env, info, want, startOptions, unwrapArgc)) { + ThrowInvalidParamError(env, "Parse param want failed, want must be Want."); + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "Input param type invalid"); + return CreateJsUndefined(env); + } + napi_value result = nullptr; + std::unique_ptr uasyncTask = CreateAsyncTaskWithLastParam(env, nullptr, nullptr, nullptr, &result); + std::shared_ptr asyncTask = std::move(uasyncTask); + RuntimeTask task = [env, asyncTask](int resultCode, const AAFwk::Want &want, bool isInner) { + TAG_LOGI(AAFwkTag::LIVE_FORM_EXT, "called"); + napi_value abilityResult = AppExecFwk::WrapAbilityResult(env, resultCode, want); + if (abilityResult == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "Wrap abilityResult failed"); + asyncTask->Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER)); + return; + } + if (isInner) { + asyncTask->Reject(env, CreateJsErrorByNativeErr(env, resultCode)); + return; + } + asyncTask->Resolve(env, abilityResult); + }; + auto context = context_.lock(); + if (context == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "The context is released"); + asyncTask->Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)); + return result; + } + want.SetParam(Want::PARAM_RESV_FOR_RESULT, true); + int curRequestCode = context->GenerateCurRequestCode(); + unwrapArgc == INDEX_ONE ? + context->StartAbilityForResultAsCaller(want, curRequestCode, std::move(task)) : + context->StartAbilityForResultAsCaller(want, startOptions, curRequestCode, std::move(task)); + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "End."); + return result; +} + +napi_value JsLiveFormExtensionContext::OnConnectAbility(napi_env env, NapiCallbackInfo& info) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called"); + // Check params count + if (info.argc < ARGC_TWO) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "invalid argc"); + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + // Unwrap want and connection + AAFwk::Want want; + sptr connection = new JSLiveFormExtensionConnection(env); + if (!AppExecFwk::UnwrapWant(env, info.argv[0], want) || + !CheckConnectionParam(env, info.argv[1], connection, want)) { + ThrowInvalidParamError(env, + "Parse param want or connection failed, want must be Want and connection must be Connection."); + return CreateJsUndefined(env); + } + int64_t connectId = connection->GetConnectionId(); + NapiAsyncTask::CompleteCallback complete = + [weak = context_, want, connection, connectId](napi_env env, NapiAsyncTask& task, int32_t status) { + auto context = weak.lock(); + if (!context) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "context is released"); + task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)); + RemoveConnection(connectId); + return; + } + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "ConnectAbility connection:%{public}d", static_cast(connectId)); + auto innerErrorCode = context->ConnectAbility(want, connection); + int32_t errcode = static_cast(AbilityRuntime::GetJsErrorCodeByNativeError(innerErrorCode)); + if (errcode) { + connection->CallJsFailed(errcode); + RemoveConnection(connectId); + } + task.Resolve(env, CreateJsUndefined(env)); + }; + napi_value result = nullptr; + NapiAsyncTask::ScheduleHighQos("JSLiveFormExtensionConnection::OnConnectAbility", + env, CreateAsyncTaskWithLastParam(env, nullptr, nullptr, std::move(complete), &result)); + return CreateJsValue(env, connectId); +} + +napi_value JsLiveFormExtensionContext::OnDisconnectAbility(napi_env env, NapiCallbackInfo& info) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "start"); + if (info.argc < ARGC_ONE) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "invalid argc"); + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + int64_t connectId = -1; + if (!AppExecFwk::UnwrapInt64FromJS2(env, info.argv[INDEX_ZERO], connectId)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "Invalid connectId"); + ThrowInvalidParamError(env, "Parse param connectId failed, connectId must be number"); + return CreateJsUndefined(env); + } + + AAFwk::Want want; + sptr connection = nullptr; + FindConnection(want, connection, connectId); + // begin disconnect + NapiAsyncTask::CompleteCallback complete = + [weak = context_, want, connection]( + napi_env env, NapiAsyncTask& task, int32_t status) { + auto context = weak.lock(); + if (!context) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "context is released"); + task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)); + return; + } + if (connection == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "connection nullptr"); + task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER)); + return; + } + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "context->DisconnectAbility"); + auto innerErrorCode = context->DisconnectAbility(want, connection); + if (innerErrorCode == 0) { + task.Resolve(env, CreateJsUndefined(env)); + } else { + task.Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode)); + } + }; + + napi_value lastParam = (info.argc == ARGC_ONE) ? nullptr : info.argv[INDEX_ONE]; + napi_value result = nullptr; + NapiAsyncTask::Schedule("JSLiveFormExtensionConnection::OnDisconnectAbility", + env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result)); + return result; +} + +napi_value JsLiveFormExtensionContext::OnReportDrawnCompleted(napi_env env, NapiCallbackInfo& info) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called"); + auto innerErrorCode = std::make_shared(ERR_OK); + NapiAsyncTask::ExecuteCallback execute = [weak = context_, innerErrorCode]() { + auto context = weak.lock(); + if (!context) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "context is released"); + *innerErrorCode = static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT); + return; + } + *innerErrorCode = context->ReportDrawnCompleted(); + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrorCode](napi_env env, NapiAsyncTask& task, int32_t status) { + if (*innerErrorCode == ERR_OK) { + task.Resolve(env, CreateJsUndefined(env)); + } else { + task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrorCode)); + } + }; + + napi_value lastParam = info.argv[INDEX_ZERO]; + napi_value result = nullptr; + NapiAsyncTask::ScheduleHighQos("JsLiveFormExtensionContext::OnReportDrawnCompleted", + env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result)); + return result; +} + +napi_value JsLiveFormExtensionContext::OnOpenAtomicService(napi_env env, NapiCallbackInfo& info) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "start"); + if (info.argc == ARGC_ZERO) { + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + + std::string appId; + if (!ConvertFromJsValue(env, info.argv[INDEX_ZERO], appId)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "OnOpenAtomicService, parse appId failed"); + ThrowInvalidParamError(env, "Parse param appId failed, appId must be string."); + return CreateJsUndefined(env); + } + + decltype(info.argc) unwrapArgc = ARGC_ONE; + Want want; + AAFwk::StartOptions startOptions; + if (info.argc > ARGC_ONE && CheckTypeForNapiValue(env, info.argv[INDEX_ONE], napi_object)) { + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "OnOpenAtomicService atomic service options is used"); + if (!AppExecFwk::UnwrapStartOptionsAndWant(env, info.argv[INDEX_ONE], startOptions, want)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "Fail to parse atomic service options"); + ThrowInvalidParamError(env, + "Parse param startOptions failed, startOptions must be StartOption."); + return CreateJsUndefined(env); + } + unwrapArgc++; + } + + std::string bundleName = ATOMIC_SERVICE_PREFIX + appId; + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "bundleName: %{public}s", bundleName.c_str()); + want.SetBundle(bundleName); + return OpenAtomicServiceInner(env, info, want, startOptions, unwrapArgc); +} + +napi_value JsLiveFormExtensionContext::OpenAtomicServiceInner(napi_env env, NapiCallbackInfo& info, Want &want, + const AAFwk::StartOptions &options, size_t unwrapArgc) +{ + want.AddFlags(Want::FLAG_INSTALL_ON_DEMAND); + std::string startTime = std::to_string(std::chrono::duration_cast(std::chrono:: + system_clock::now().time_since_epoch()).count()); + want.SetParam(Want::PARAM_RESV_START_TIME, startTime); + napi_value result = nullptr; + AddFreeInstallObserver(env, want, nullptr, &result, true); + RuntimeTask task = [env, element = want.GetElement(), startTime, &observer = freeInstallObserver_]( + int resultCode, const AAFwk::Want& want, bool isInner) { + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "OnOpenAtomicService async callback is begin"); + if (observer == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "observer is nullptr"); + return; + } + HandleScope handleScope(env); + std::string bundleName = element.GetBundleName(); + std::string abilityName = element.GetAbilityName(); + napi_value abilityResult = AppExecFwk::WrapAbilityResult(env, resultCode, want); + if (abilityResult == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "wrap abilityResult failed"); + isInner = true; + resultCode = ERR_INVALID_VALUE; + } + if (isInner) { + observer->OnInstallFinished(bundleName, abilityName, startTime, resultCode); + } else { + observer->OnInstallFinished(bundleName, abilityName, startTime, abilityResult); + } + }; + auto context = context_.lock(); + if (context == nullptr) { + TAG_LOGW(AAFwkTag::LIVE_FORM_EXT, "context is released"); + ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT); + return CreateJsUndefined(env); + } else { + want.SetParam(Want::PARAM_RESV_FOR_RESULT, true); + auto curRequestCode = context->GenerateCurRequestCode(); + context->OpenAtomicService(want, options, curRequestCode, std::move(task)); + } + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "end"); + return result; +} + +void JsLiveFormExtensionContext::AddFreeInstallObserver(napi_env env, const AAFwk::Want &want, napi_value callback, + napi_value *result, bool isAbilityResult, bool isOpenLink) +{ + // adapter free install async return install and start result + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "begin"); + int ret = 0; + if (freeInstallObserver_ == nullptr) { + freeInstallObserver_ = new JsFreeInstallObserver(env); + auto context = context_.lock(); + if (!context) { + TAG_LOGE(AAFwkTag::CONTEXT, "context is nullptr."); + return; + } + ret = context->AddFreeInstallObserver(freeInstallObserver_); + } + + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "AddFreeInstallObserver error"); + } + std::string startTime = want.GetStringParam(Want::PARAM_RESV_START_TIME); + if (!isOpenLink) { + TAG_LOGI(AAFwkTag::LIVE_FORM_EXT, "AddJsObserverObject"); + std::string bundleName = want.GetElement().GetBundleName(); + std::string abilityName = want.GetElement().GetAbilityName(); + freeInstallObserver_->AddJsObserverObject( + bundleName, abilityName, startTime, callback, result, isAbilityResult); + } + std::string url = want.GetUriString(); + freeInstallObserver_->AddJsObserverObject(startTime, url, callback, result, isAbilityResult); +} + +napi_value JsLiveFormExtensionContext::CreateJsLiveFormExtensionContext(napi_env env, + std::shared_ptr context) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "begin"); + std::shared_ptr abilityInfo = nullptr; + if (context) { + abilityInfo = context->GetAbilityInfo(); + } + napi_value objValue = CreateJsExtensionContext(env, context, abilityInfo); + + std::unique_ptr jsContext = std::make_unique(context); + napi_wrap(env, objValue, jsContext.release(), Finalizer, nullptr, nullptr); + + const char *moduleName = "JsLiveFormExtensionContext"; + BindNativeFunction(env, objValue, "startAbility", moduleName, StartAbility); + BindNativeFunction(env, objValue, "openLink", moduleName, OpenLink); + BindNativeFunction(env, objValue, "startAbilityForResult", moduleName, StartAbilityForResult); + BindNativeFunction(env, objValue, "startAbilityForResultAsCaller", moduleName, StartAbilityForResultAsCaller); + BindNativeFunction(env, objValue, "connectServiceExtensionAbility", moduleName, ConnectAbility); + BindNativeFunction(env, objValue, "disconnectServiceExtensionAbility", moduleName, DisconnectAbility); + BindNativeFunction(env, objValue, "reportDrawnCompleted", moduleName, ReportDrawnCompleted); + BindNativeFunction(env, objValue, "openAtomicService", moduleName, OpenAtomicService); + + return objValue; +} + +bool JsLiveFormExtensionContext::CheckStartAbilityInputParam(napi_env env, NapiCallbackInfo& info, + AAFwk::Want& want, AAFwk::StartOptions& startOptions, size_t& unwrapArgc) const +{ + if (info.argc < ARGC_ONE) { + return false; + } + unwrapArgc = ARGC_ZERO; + // Check input want + if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) { + return false; + } + if (!want.HasParameter(Want::PARAM_BACK_TO_OTHER_MISSION_STACK)) { + want.SetParam(Want::PARAM_BACK_TO_OTHER_MISSION_STACK, true); + } + ++unwrapArgc; + if (info.argc > ARGC_ONE && CheckTypeForNapiValue(env, info.argv[1], napi_object)) { + AppExecFwk::UnwrapStartOptions(env, info.argv[1], startOptions); + unwrapArgc++; + } + return true; +} + +JSLiveFormExtensionConnection::JSLiveFormExtensionConnection(napi_env env) : env_(env) {} + +JSLiveFormExtensionConnection::~JSLiveFormExtensionConnection() +{ + ReleaseNativeReference(jsConnectionObject_.release()); +} + +void JSLiveFormExtensionConnection::ReleaseNativeReference(NativeReference* ref) +{ + if (ref == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "ReleaseNativeReference: ref == nullptr"); + return; + } + uv_loop_t *loop = nullptr; + napi_get_uv_event_loop(env_, &loop); + if (loop == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "ReleaseNativeReference: failed to get uv loop."); + delete ref; + return; + } + uv_work_t *work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "ReleaseNativeReference: failed to create work."); + delete ref; + return; + } + work->data = reinterpret_cast(ref); + int ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, + [](uv_work_t *work, int status) { + if (work == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "ReleaseNativeReference: work is nullptr."); + return; + } + if (work->data == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "ReleaseNativeReference: data is nullptr."); + delete work; + work = nullptr; + return; + } + NativeReference *refPtr = reinterpret_cast(work->data); + delete refPtr; + refPtr = nullptr; + delete work; + work = nullptr; + }); + if (ret != 0) { + delete ref; + if (work != nullptr) { + delete work; + work = nullptr; + } + } +} + +void JSLiveFormExtensionConnection::SetConnectionId(int64_t id) +{ + connectionId_ = id; +} + +int64_t JSLiveFormExtensionConnection::GetConnectionId() +{ + return connectionId_; +} + +void JSLiveFormExtensionConnection::OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "resultCode:%{public}d", resultCode); + wptr connection = this; + std::unique_ptr complete = std::make_unique + ([connection, element, remoteObject, resultCode](napi_env env, NapiAsyncTask &task, int32_t status) { + sptr connectionSptr = connection.promote(); + if (!connectionSptr) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "connectionSptr nullptr"); + return; + } + connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode); + }); + + napi_ref callback = nullptr; + std::unique_ptr execute = nullptr; + NapiAsyncTask::ScheduleHighQos("JSLiveFormExtensionConnection::OnAbilityConnectDone", + env_, std::make_unique(callback, std::move(execute), std::move(complete))); +} + +void JSLiveFormExtensionConnection::HandleOnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "start, resultCode:%{public}d", resultCode); + // wrap ElementName + napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element); + + // wrap RemoteObject + napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(env_, remoteObject); + napi_value argv[] = {napiElementName, napiRemoteObject}; + if (jsConnectionObject_ == nullptr) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "jsConnectionObject_ null"); + return; + } + napi_value obj = jsConnectionObject_->GetNapiValue(); + if (!CheckTypeForNapiValue(env_, obj, napi_object)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "Failed to get object"); + return; + } + napi_value methodOnConnect = nullptr; + napi_get_named_property(env_, obj, "onConnect", &methodOnConnect); + if (methodOnConnect == nullptr) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "Failed to get onConnect from object"); + return; + } + napi_call_function(env_, obj, methodOnConnect, ARGC_TWO, argv, nullptr); +} + +void JSLiveFormExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "resultCode:%{public}d", resultCode); + wptr connection = this; + std::unique_ptr complete = std::make_unique + ([connection, element, resultCode](napi_env env, NapiAsyncTask &task, int32_t status) { + sptr connectionSptr = connection.promote(); + if (!connectionSptr) { + TAG_LOGI(AAFwkTag::LIVE_FORM_EXT, "connectionSptr nullptr"); + return; + } + connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode); + }); + napi_ref callback = nullptr; + std::unique_ptr execute = nullptr; + NapiAsyncTask::Schedule("JSLiveFormExtensionConnection::OnAbilityDisconnectDone", + env_, std::make_unique(callback, std::move(execute), std::move(complete))); +} + +void JSLiveFormExtensionConnection::HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element, + int resultCode) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "resultCode:%{public}d", resultCode); + napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element); + napi_value argv[] = {napiElementName}; + if (jsConnectionObject_ == nullptr) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "jsConnectionObject_ nullptr"); + return; + } + napi_value obj = jsConnectionObject_->GetNapiValue(); + if (!CheckTypeForNapiValue(env_, obj, napi_object)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "Failed to get object"); + return; + } + napi_value method = nullptr; + napi_get_named_property(env_, obj, "onDisconnect", &method); + if (method == nullptr) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "Failed to get onDisconnect from object"); + return; + } + + // release connect + RemoveConnection(connectionId_); + napi_call_function(env_, obj, method, ARGC_ONE, argv, nullptr); +} + +void JSLiveFormExtensionConnection::SetJsConnectionObject(napi_value jsConnectionObject) +{ + napi_ref value = nullptr; + napi_create_reference(env_, jsConnectionObject, 1, &value); + jsConnectionObject_ = std::unique_ptr(reinterpret_cast(value)); +} + +void JSLiveFormExtensionConnection::RemoveConnectionObject() +{ + jsConnectionObject_.reset(); +} + +void JSLiveFormExtensionConnection::CallJsFailed(int32_t errorCode) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "CallJsFailed enter"); + if (jsConnectionObject_ == nullptr) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "jsConnectionObject_ nullptr"); + return; + } + napi_value obj = jsConnectionObject_->GetNapiValue(); + if (!CheckTypeForNapiValue(env_, obj, napi_object)) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "wrong to get object"); + return; + } + + napi_value method = nullptr; + napi_get_named_property(env_, obj, "onFailed", &method); + if (method == nullptr) { + TAG_LOGE(AAFwkTag::LIVE_FORM_EXT, "Failed to get onFailed from object"); + return; + } + napi_value argv[] = { CreateJsValue(env_, errorCode) }; + napi_call_function(env_, obj, method, ARGC_ONE, argv, nullptr); + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "CallJsFailed end"); +} + +napi_value JSLiveFormExtensionConnection::CallObjectMethod(const char* name, napi_value const *argv, size_t argc) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "name:%{public}s", name); + if (!jsConnectionObject_) { + TAG_LOGW(AAFwkTag::CONTEXT, "Not found jsConnectionObject_"); + return nullptr; + } + + HandleScope handleScope(env_); + napi_value obj = jsConnectionObject_->GetNapiValue(); + if (!CheckTypeForNapiValue(env_, obj, napi_object)) { + TAG_LOGE(AAFwkTag::CONTEXT, "Failed to get jsConnectionObject_ object"); + return nullptr; + } + + napi_value method = nullptr; + napi_get_named_property(env_, obj, name, &method); + if (!CheckTypeForNapiValue(env_, method, napi_function)) { + TAG_LOGE(AAFwkTag::CONTEXT, "Failed to get '%{public}s' from jsConnectionObject_ object", name); + return nullptr; + } + napi_value result = nullptr; + napi_call_function(env_, obj, method, argc, argv, &result); + TAG_LOGD(AAFwkTag::CONTEXT, "CallFunction(%{public}s) ok", name); + return result; +} + +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/ability/native/live_form_extension_ability/live_form_extension.cpp b/frameworks/native/ability/native/live_form_extension_ability/live_form_extension.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c417b18a38a11be88a056cf652a5547331cdfacb --- /dev/null +++ b/frameworks/native/ability/native/live_form_extension_ability/live_form_extension.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "live_form_extension.h" + +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "js_live_form_extension.h" +#include "runtime.h" +#include "ui_extension_context.h" + +namespace OHOS { +namespace AbilityRuntime { +LiveFormExtension *LiveFormExtension::Create(const std::unique_ptr &runtime) +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called."); + if (!runtime) { + return new LiveFormExtension(); + } + switch (runtime->GetLanguage()) { + case Runtime::Language::JS: + return JsLiveFormExtension::Create(runtime); + default: + return new LiveFormExtension(); + } +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/ability/native/live_form_extension_ability/live_form_extension_context.cpp b/frameworks/native/ability/native/live_form_extension_ability/live_form_extension_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7dca2518d140056c1244521ad489bab7f9cbee7 --- /dev/null +++ b/frameworks/native/ability/native/live_form_extension_ability/live_form_extension_context.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "live_form_extension_context.h" + +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" + +namespace OHOS { +namespace AbilityRuntime { +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/ability/native/live_form_extension_ability/live_form_extension_module_loader.cpp b/frameworks/native/ability/native/live_form_extension_ability/live_form_extension_module_loader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad4dd9eae8fb3df1bc256ac7e2a500a26f8fe01a --- /dev/null +++ b/frameworks/native/ability/native/live_form_extension_ability/live_form_extension_module_loader.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "live_form_extension_module_loader.h" + +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "live_form_extension.h" + +namespace OHOS { +namespace AbilityRuntime { +LiveFormExtensionModuleLoader::LiveFormExtensionModuleLoader() = default; +LiveFormExtensionModuleLoader::~LiveFormExtensionModuleLoader() = default; + +Extension *LiveFormExtensionModuleLoader::Create(const std::unique_ptr &runtime) const +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called"); + return LiveFormExtension::Create(runtime); +} + +std::map LiveFormExtensionModuleLoader::GetParams() +{ + TAG_LOGD(AAFwkTag::LIVE_FORM_EXT, "called"); + std::map params; + // type means extension type in ExtensionAbilityType of + // extension_ability_info.h, 24 means liveformextension. + params.insert(std::pair("type", "24")); + params.insert(std::pair("name", "LiveFormExtensionAbility")); + return params; +} + +extern "C" __attribute__((visibility("default"))) void *OHOS_EXTENSION_GetExtensionModule() +{ + return &LiveFormExtensionModuleLoader::GetInstance(); +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/native/ability/native/live_form_extension_ability/js_live_form_extension.h b/interfaces/kits/native/ability/native/live_form_extension_ability/js_live_form_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..68e04646c8d7817ea410c23d1612b4de0f4eed64 --- /dev/null +++ b/interfaces/kits/native/ability/native/live_form_extension_ability/js_live_form_extension.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_JS_LIVE_FORM_EXTENSION_H +#define OHOS_ABILITY_RUNTIME_JS_LIVE_FORM_EXTENSION_H + +#include "configuration.h" +#include "live_form_extension.h" + +class NativeReference; + +namespace OHOS { +namespace AbilityRuntime { +class LiveFormExtension; +class JsRuntime; +class JsUIExtensionBase; +/** + * @brief Basic share extension components. + */ +class JsLiveFormExtension : public LiveFormExtension, public std::enable_shared_from_this { +public: + explicit JsLiveFormExtension(const std::unique_ptr &runtime); + virtual ~JsLiveFormExtension() override; + + /** + * @brief Create JsLiveFormExtension. + * + * @param runtime The runtime. + * @return The JsLiveFormExtension instance. + */ + static JsLiveFormExtension *Create(const std::unique_ptr &runtime); +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_JS_LIVE_FORM_EXTENSION_H \ No newline at end of file diff --git a/interfaces/kits/native/ability/native/live_form_extension_ability/js_live_form_extension_context.h b/interfaces/kits/native/ability/native/live_form_extension_ability/js_live_form_extension_context.h new file mode 100644 index 0000000000000000000000000000000000000000..606e086513e31dd4ed93a32b213b1666760c9099 --- /dev/null +++ b/interfaces/kits/native/ability/native/live_form_extension_ability/js_live_form_extension_context.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_JS_LIVE_FORM_EXTENSION_CONTEXT_H +#define OHOS_ABILITY_RUNTIME_JS_LIVE_FORM_EXTENSION_CONTEXT_H + +#include + +#include "live_form_extension_context.h" +#include "js_free_install_observer.h" +#include "native_engine/native_engine.h" + + +namespace OHOS { +namespace AbilityRuntime { +struct NapiCallbackInfo; +class JsEmbeddableUIAbilityContext; + +class JsLiveFormExtensionContext final { +public: + explicit JsLiveFormExtensionContext(const std::shared_ptr &context) : context_(context) {} + virtual ~JsLiveFormExtensionContext() = default; + static void Finalizer(napi_env env, void* data, void* hint); + static napi_value StartAbility(napi_env env, napi_callback_info info); + static napi_value OpenLink(napi_env env, napi_callback_info info); + static napi_value CreateJsLiveFormExtensionContext(napi_env env, std::shared_ptr context); + static napi_value StartAbilityForResult(napi_env env, napi_callback_info info); + static napi_value StartAbilityForResultAsCaller(napi_env env, napi_callback_info info); + static napi_value ConnectAbility(napi_env env, napi_callback_info info); + static napi_value DisconnectAbility(napi_env env, napi_callback_info info); + static napi_value ReportDrawnCompleted(napi_env env, napi_callback_info info); + static napi_value OpenAtomicService(napi_env env, napi_callback_info info); + +protected: + virtual napi_value OnStartAbility(napi_env env, NapiCallbackInfo& info); + virtual napi_value OnStartAbilityForResult(napi_env env, NapiCallbackInfo& info); + virtual napi_value OnStartAbilityForResultAsCaller(napi_env env, NapiCallbackInfo &info); + virtual napi_value OnConnectAbility(napi_env env, NapiCallbackInfo& info); + virtual napi_value OnDisconnectAbility(napi_env env, NapiCallbackInfo& info); + virtual napi_value OnReportDrawnCompleted(napi_env env, NapiCallbackInfo& info); + virtual napi_value OnOpenAtomicService(napi_env env, NapiCallbackInfo& info); + +protected: + std::weak_ptr context_; +private: + sptr freeInstallObserver_ = nullptr; + friend class JsEmbeddableUIAbilityContext; + bool CheckStartAbilityInputParam(napi_env env, NapiCallbackInfo& info, AAFwk::Want& want, + AAFwk::StartOptions& startOptions, size_t& unwrapArgc) const; + napi_value OpenAtomicServiceInner(napi_env env, NapiCallbackInfo& info, AAFwk::Want &want, + const AAFwk::StartOptions &options, size_t unwrapArgc); + void AddFreeInstallObserver(napi_env env, const AAFwk::Want &want, napi_value callback, napi_value* result, + bool isAbilityResult = false, bool isOpenLink = false); + bool CreateOpenLinkTask(const napi_env &env, const napi_value &lastParam, + AAFwk::Want &want, int &requestCode); + void RemoveOpenLinkTask(int requestCode); + napi_value OnOpenLink(napi_env env, NapiCallbackInfo& info); + napi_value OnOpenLinkInner(napi_env env, const AAFwk::Want& want, + int requestCode, const std::string& startTime, const std::string& url); +}; + +class JSLiveFormExtensionConnection : public AbilityConnectCallback { +public: + explicit JSLiveFormExtensionConnection(napi_env env); + ~JSLiveFormExtensionConnection(); + void ReleaseNativeReference(NativeReference* ref); + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + virtual void HandleOnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode); + virtual void HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode); + void SetJsConnectionObject(napi_value jsConnectionObject); + std::unique_ptr& GetJsConnectionObject() { return jsConnectionObject_; } + void RemoveConnectionObject(); + void CallJsFailed(int32_t errorCode); + napi_value CallObjectMethod(const char* name, napi_value const *argv, size_t argc); + void SetConnectionId(int64_t id); + int64_t GetConnectionId(); +protected: + napi_env env_ = nullptr; + std::unique_ptr jsConnectionObject_ = nullptr; + int64_t connectionId_ = -1; +}; + +struct LiveFormExtensionConnectionKey { + AAFwk::Want want; + int64_t id; +}; + +struct key_compare { + bool operator()(const LiveFormExtensionConnectionKey &key1, const LiveFormExtensionConnectionKey &key2) const + { + if (key1.id < key2.id) { + return true; + } + return false; + } +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_JS_LIVE_FORM_EXTENSION_CONTEXT_H \ No newline at end of file diff --git a/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension.h b/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..a88b6c2de8bffd7a38697dd72a67a12ba0d7b727 --- /dev/null +++ b/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_H +#define OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_H + +#include "ui_extension_base.h" + +namespace OHOS { +namespace AbilityRuntime { +class UIExtensionContext; +class Runtime; +/** + * @brief Share extension components. + */ +class LiveFormExtension : public UIExtensionBase, + public std::enable_shared_from_this { +public: + LiveFormExtension() = default; + virtual ~LiveFormExtension() = default; + + /** + * @brief Create share extension. + * + * @param runtime The runtime. + * @return The share extension instance. + */ + static LiveFormExtension *Create(const std::unique_ptr &runtime); +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_H \ No newline at end of file diff --git a/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension_context.h b/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension_context.h new file mode 100644 index 0000000000000000000000000000000000000000..6c125282597a34d63e3d22322fe7a1b9816b3ef7 --- /dev/null +++ b/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension_context.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_CONTEXT_H +#define OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_CONTEXT_H + +#include "ui_extension_context.h" + +namespace OHOS { +namespace AbilityRuntime { + +class LiveFormExtensionContext : public UIExtensionContext { +public: + LiveFormExtensionContext() = default; + virtual ~LiveFormExtensionContext() = default; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_CONTEXT_H \ No newline at end of file diff --git a/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension_module_loader.h b/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension_module_loader.h new file mode 100644 index 0000000000000000000000000000000000000000..9935ba81c07e7baaaf17a145aaf147597855b038 --- /dev/null +++ b/interfaces/kits/native/ability/native/live_form_extension_ability/live_form_extension_module_loader.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_MODULE_LOADER_H +#define OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_MODULE_LOADER_H + +#include "extension_module_loader.h" + +namespace OHOS { +namespace AbilityRuntime { +class LiveFormExtensionModuleLoader : public ExtensionModuleLoader, public Singleton { + DECLARE_SINGLETON(LiveFormExtensionModuleLoader); + +public: + /** + * @brief Create Extension. + * + * @param runtime The runtime. + * @return The Extension instance. + */ + Extension *Create(const std::unique_ptr &runtime) const override; + + /** + * @brief Get the Params object + * + * @return std::map The map of extension type and extension name. + */ + std::map GetParams() override; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_LIVE_FORM_EXTENSION_MODULE_LOADER_H \ No newline at end of file diff --git a/services/common/include/hilog_tag_wrapper.h b/services/common/include/hilog_tag_wrapper.h index 90ab678439316a16b4a1456a7e62f37eb56cf0e4..b841d916ad7083f9d4dc775e636e4da3c579452e 100644 --- a/services/common/include/hilog_tag_wrapper.h +++ b/services/common/include/hilog_tag_wrapper.h @@ -77,7 +77,8 @@ enum class AAFwkLogTag : uint32_t { ACTION_EXT, EMBEDDED_EXT, UISERVC_EXT, - + LIVE_FORM_EXT, + WANTAGENT = DEFAULT + 0x50, // 0xD001350 AUTOFILLMGR, EXTMGR, diff --git a/services/common/include/ui_extension_utils.h b/services/common/include/ui_extension_utils.h index 9873fd01b4354d3636c8be3e7d430779f37ee204..39afaf82dedcce0108c83ca67601f3b06c513c27 100755 --- a/services/common/include/ui_extension_utils.h +++ b/services/common/include/ui_extension_utils.h @@ -64,7 +64,8 @@ inline std::unordered_set GetUiExtensionSet() AppExecFwk::ExtensionAbilityType::SYSPICKER_PHOTOEDITOR, AppExecFwk::ExtensionAbilityType::PHOTO_EDITOR, AppExecFwk::ExtensionAbilityType::SYSPICKER_AUDIOPICKER, - AppExecFwk::ExtensionAbilityType::SYS_VISUAL + AppExecFwk::ExtensionAbilityType::SYS_VISUAL, + AppExecFwk::ExtensionAbilityType::LIVE_FORM }; } @@ -116,7 +117,8 @@ inline bool IsSystemCallerNeeded(const AppExecFwk::ExtensionAbilityType type) AppExecFwk::ExtensionAbilityType::SHARE, AppExecFwk::ExtensionAbilityType::ACTION, AppExecFwk::ExtensionAbilityType::STATUS_BAR_VIEW, - AppExecFwk::ExtensionAbilityType::VOIP + AppExecFwk::ExtensionAbilityType::VOIP, + AppExecFwk::ExtensionAbilityType::LIVE_FORM }; return uiExtensionStartingSet.find(type) != uiExtensionStartingSet.end(); } diff --git a/test/unittest/frameworks_kits_ability_native_test/BUILD.gn b/test/unittest/frameworks_kits_ability_native_test/BUILD.gn index d83e2763c82e5a5e6e2c8ef8f7353ea4a12197ef..59cba2d036b719b6e6eb7bfb874cf3abf0b87ab3 100644 --- a/test/unittest/frameworks_kits_ability_native_test/BUILD.gn +++ b/test/unittest/frameworks_kits_ability_native_test/BUILD.gn @@ -2608,6 +2608,74 @@ ohos_unittest("share_extension_test") { ] } +ohos_unittest("live_form_extension_module_loader_test") { + module_out_path = module_output_path + include_dirs = [ "${ability_runtime_path}/interfaces/kits/native/ability/native/live_form_extension_ability" ] + + sources = [ + "${ability_runtime_native_path}/ability/native/live_form_extension_ability/live_form_extension_module_loader.cpp", + "live_form_extension_module_loader_test.cpp", + ] + + configs = [ ":module_private_config" ] + + deps = [ + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/ability/native:abilitykit_native", + "${ability_runtime_native_path}/ability/native:live_form_extension", + "${ability_runtime_native_path}/ability/native:ui_extension", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_native_path}/appkit:appkit_native", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "bundle_framework:appexecfwk_base", + "c_utils:utils", + "hilog:libhilog", + "init:libbegetutil", + "ipc:ipc_core", + "napi:ace_napi", + ] +} + +ohos_unittest("live_form_extension_test") { + module_out_path = module_output_path + include_dirs = [ + "${ability_runtime_test_path}/mock/frameworks_kits_ability_native_test/include", + "${ability_runtime_path}/interfaces/kits/native/ability/native/live_form_extension_ability", + ] + + sources = [ "live_form_extension_test.cpp" ] + + configs = [ ":module_private_config" ] + + deps = [ + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/ability/native:abilitykit_native", + "${ability_runtime_native_path}/ability/native:live_form_extension", + "${ability_runtime_native_path}/ability/native:ui_extension", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_native_path}/appkit:appkit_native", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "ability_base:base", + "ability_base:want", + "bundle_framework:appexecfwk_base", + "c_utils:utils", + "eventhandler:libeventhandler", + "hilog:libhilog", + "init:libbegetutil", + "ipc:ipc_core", + "napi:ace_napi", + ] +} + ohos_unittest("auto_fill_extension_module_loader_test") { module_out_path = module_output_path include_dirs = [ "${ability_runtime_path}/interfaces/kits/native/ability/native/auto_fill_extension_ability" ] @@ -2891,6 +2959,8 @@ group("unittest") { ":fa_ability_thread_test", ":form_extension_test", ":js_ui_extension_Callback_test", + ":live_form_extension_module_loader_test", + ":live_form_extension_test", ":new_ability_impl_test", ":pac_map_test", ":reserse_continuation_scheduler_primary_proxy_test", diff --git a/test/unittest/frameworks_kits_ability_native_test/live_form_extension_module_loader_test.cpp b/test/unittest/frameworks_kits_ability_native_test/live_form_extension_module_loader_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a19f42119350a6b27e87da08128f1e312c6fe4e1 --- /dev/null +++ b/test/unittest/frameworks_kits_ability_native_test/live_form_extension_module_loader_test.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 + +#include "ability_handler.h" +#include "mock_ability_token.h" +#include "ohos_application.h" +#include "runtime.h" +#include "live_form_extension.h" + +namespace OHOS { +namespace AbilityRuntime { +using namespace testing::ext; + +class LiveFormExtensionTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void LiveFormExtensionTest::SetUpTestCase(void) +{} + +void LiveFormExtensionTest::TearDownTestCase(void) +{} + +void LiveFormExtensionTest::SetUp(void) +{} + +void LiveFormExtensionTest::TearDown(void) +{} + +/** + * @tc.number: Live_Form_Extension_0100 + * @tc.name: Create + * @tc.desc: The runtime is nullptr, and the verification of create succeeds. + */ +HWTEST_F(LiveFormExtensionTest, Live_Form_Extension_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Live_Form_Extension_0100 start"; + std::unique_ptr runtime; + auto liveFormExtension = LiveFormExtension::Create(runtime); + EXPECT_TRUE(liveFormExtension != nullptr); + GTEST_LOG_(INFO) << "Live_Form_Extension_0100 end"; +} + +/** + * @tc.number: Live_Form_Extension_0200 + * @tc.name: Create + * @tc.desc: The language is js, and the verification of create is successful. + */ +HWTEST_F(LiveFormExtensionTest, Live_Form_Extension_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Live_Form_Extension_0200 start"; + Runtime::Options options; + auto runtime = Runtime::Create(options); + auto liveFormExtension = LiveFormExtension::Create(runtime); + EXPECT_TRUE(liveFormExtension != nullptr); + GTEST_LOG_(INFO) << "Live_Form_Extension_0200 end"; +} + +/** + * @tc.number: Live_Form_Extension_0300 + * @tc.name: Init + * @tc.desc: Validation initialization succeeded. + */ +HWTEST_F(LiveFormExtensionTest, Live_Form_Extension_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Live_Form_Extension_0300 start"; + auto abilityInfo = std::make_shared(); + sptr token = new AppExecFwk::MockAbilityToken(); + auto record = std::make_shared(abilityInfo, token); + auto application = std::make_shared(); + auto contextImpl = std::make_shared(); + auto applicationContext = ApplicationContext::GetInstance(); + applicationContext->AttachContextImpl(contextImpl); + application->SetApplicationContext(applicationContext); + auto handler = std::make_shared(nullptr); + Runtime::Options options; + std::unique_ptr runtime = Runtime::Create(options); + auto liveFormExtension = LiveFormExtension::Create(runtime); + liveFormExtension->Init(record, application, handler, token); + EXPECT_TRUE(liveFormExtension != nullptr); + GTEST_LOG_(INFO) << "Live_Form_Extension_0300 end"; +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/frameworks_kits_ability_native_test/live_form_extension_test.cpp b/test/unittest/frameworks_kits_ability_native_test/live_form_extension_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d89cc89e143ca2d2999b82dc3029bcef55a7032 --- /dev/null +++ b/test/unittest/frameworks_kits_ability_native_test/live_form_extension_test.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 + +#include "ability_handler.h" +#include "live_form_extension.h" +#include "mock_ability_token.h" +#include "ohos_application.h" +#include "runtime.h" + +namespace OHOS { +namespace AbilityRuntime { +using namespace testing::ext; + +class LiveFormExtensionTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void LiveFormExtensionTest::SetUpTestCase(void) +{} + +void LiveFormExtensionTest::TearDownTestCase(void) +{} + +void LiveFormExtensionTest::SetUp(void) +{} + +void LiveFormExtensionTest::TearDown(void) +{} + +/** + * @tc.number: Live_Form_Extension_0100 + * @tc.name: Create + * @tc.desc: The runtime is nullptr, and the verification of create succeeds. + */ +HWTEST_F(LiveFormExtensionTest, Live_Form_Extension_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Live_Form_Extension_0100 start"; + std::unique_ptr runtime; + auto liveFormExtension = LiveFormExtension::Create(runtime); + EXPECT_TRUE(liveFormExtension != nullptr); + GTEST_LOG_(INFO) << "Live_Form_Extension_0100 end"; +} + +/** + * @tc.number: Live_Form_Extension_0200 + * @tc.name: Create + * @tc.desc: The language is js, and the verification of create is successful. + */ +HWTEST_F(LiveFormExtensionTest, Live_Form_Extension_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Live_Form_Extension_0200 start"; + Runtime::Options options; + auto runtime = Runtime::Create(options); + auto liveFormExtension = LiveFormExtension::Create(runtime); + EXPECT_TRUE(liveFormExtension != nullptr); + GTEST_LOG_(INFO) << "Live_Form_Extension_0200 end"; +} + +/** + * @tc.number: Live_Form_Extension_0300 + * @tc.name: Init + * @tc.desc: Validation initialization succeeded. + */ +HWTEST_F(LiveFormExtensionTest, Live_Form_Extension_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Live_Form_Extension_0300 start"; + auto abilityInfo = std::make_shared(); + sptr token = new AppExecFwk::MockAbilityToken(); + auto record = std::make_shared(abilityInfo, token); + auto application = std::make_shared(); + auto contextImpl = std::make_shared(); + auto applicationContext = ApplicationContext::GetInstance(); + applicationContext->AttachContextImpl(contextImpl); + application->SetApplicationContext(applicationContext); + auto handler = std::make_shared(nullptr); + Runtime::Options options; + std::unique_ptr runtime = Runtime::Create(options); + auto liveFormExtension = LiveFormExtension::Create(runtime); + liveFormExtension->Init(record, application, handler, token); + EXPECT_TRUE(liveFormExtension != nullptr); + GTEST_LOG_(INFO) << "Live_Form_Extension_0300 end"; +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file