From afe3b6fc6cc824728e27855f2fe59cc00af0e513 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Sat, 2 Aug 2025 05:35:47 -0400 Subject: [PATCH] connectUIServiceExtensionAbility startUIServiceExtensionAbility disconnectUIServiceExtensionAbility Signed-off-by: zhangzezhong --- .../include/ets_ui_extension_context.h | 10 + .../include/ets_uiservice_uiext_connection.h | 62 +++++ .../src/ets_ui_extension_context.cpp | 126 ++++++++- .../src/ets_uiservice_uiext_connection.cpp | 259 ++++++++++++++++++ .../application/ServiceExtensionContext.ets | 17 ++ .../ets/ets/application/UIAbilityContext.ets | 53 +++- .../ets/application/UIExtensionContext.ets | 51 ++++ .../UIServiceExtensionConnectCallback.ets | 24 ++ 8 files changed, 599 insertions(+), 3 deletions(-) create mode 100644 frameworks/ets/ani/ui_extension_ability/include/ets_uiservice_uiext_connection.h create mode 100644 frameworks/ets/ani/ui_extension_ability/src/ets_uiservice_uiext_connection.cpp create mode 100644 frameworks/ets/ets/application/UIServiceExtensionConnectCallback.ets diff --git a/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_context.h b/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_context.h index 4df327ef93b..c4be804939d 100644 --- a/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_context.h +++ b/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_context.h @@ -73,6 +73,12 @@ public: ani_object startOptionsObj, ani_object callback); static void SetColorMode(ani_env *env, ani_object aniObj, ani_enum_item aniColorMode); static void ReportDrawnCompleted(ani_env *env, ani_object aniObj, ani_object callback); + static void ConnectUIServiceExtension(ani_env *env, ani_object aniObj, ani_object wantObj, + ani_object uiServiceExtConCallbackObj, ani_object callback); + static void StartUIServiceExtension(ani_env *env, ani_object aniObj, + ani_object wantObj, ani_object callback); + static void DisconnectUIServiceExtension(ani_env *env, ani_object aniObj, ani_obj proxyObj, + ani_object callback); static bool BindNativePtrCleaner(ani_env *env); static void Clean(ani_env *env, ani_object object); @@ -93,6 +99,10 @@ private: sptr& connection, AAFwk::Want& want); void OnSetColorMode(ani_env *env, ani_object aniCls, ani_enum_item aniColorMode); void OnReportDrawnCompleted(ani_env *env, ani_object aniCls, ani_object callback); + void OnConnectUIServiceExtension(ani_env *env, ani_object wantObj, ani_object uiServiceExtConCallbackObj, + ani_object callback); + void OnStartUIServiceExtension(ani_env *env, ani_object wantObj, ani_object callback); + void OnDisconnectUIServiceExtension(ani_env *env, ani_obj proxyObj, ani_object callback); protected: std::weak_ptr context_; diff --git a/frameworks/ets/ani/ui_extension_ability/include/ets_uiservice_uiext_connection.h b/frameworks/ets/ani/ui_extension_ability/include/ets_uiservice_uiext_connection.h new file mode 100644 index 00000000000..810d51a7c2a --- /dev/null +++ b/frameworks/ets/ani/ui_extension_ability/include/ets_uiservice_uiext_connection.h @@ -0,0 +1,62 @@ +/* + * 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_UISERVICE_UIEXT_CONNECTION_H +#define OHOS_ABILITY_RUNTIME_UISERVICE_UIEXT_CONNECTION_H + +#include "js_ui_extension_context.h" + +#include "ui_service_host_stub.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace UIServiceConnection { +void AddUIServiceExtensionConnection(AAFwk::Want& want, sptr& connection); +void RemoveUIServiceExtensionConnection(const int64_t& connectId); +void FindUIServiceExtensionConnection(const int64_t& connectId, AAFwk::Want& want, + sptr& connection); +void FindUIServiceExtensionConnection(napi_env env, AAFwk::Want& want, napi_value callback, + sptr& connection); +} + +class UIExtensionServiceHostStubImpl; +class JSUIServiceUIExtConnection : public JSUIExtensionConnection { +public: + JSUIServiceUIExtConnection(napi_env env); + ~JSUIServiceUIExtConnection(); + virtual void HandleOnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + virtual void HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + sptr GetServiceHostStub() { return serviceHostStub_; } + void SetProxyObject(napi_value proxy); + napi_value GetProxyObject(); + void SetNapiAsyncTask(std::shared_ptr& task); + void AddDuplicatedPendingTask(std::unique_ptr& task); + void ResolveDuplicatedPendingTask(napi_env env, napi_value proxy); + void RejectDuplicatedPendingTask(napi_env env, napi_value error); + int32_t OnSendData(OHOS::AAFwk::WantParams &data); + void HandleOnSendData(const OHOS::AAFwk::WantParams &data); + void CallJsOnDisconnect(); + static bool IsJsCallbackObjectEquals(napi_env env, std::unique_ptr& callback, napi_value value); + +private: + sptr serviceHostStub_; + std::unique_ptr serviceProxyObject_; + std::shared_ptr napiAsyncTask_; + std::vector> duplicatedPendingTaskList_; +}; + +} +} +#endif diff --git a/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp b/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp index 59228da3ffe..63081456228 100644 --- a/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp +++ b/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp @@ -564,6 +564,118 @@ void EtsUIExtensionContext::OnReportDrawnCompleted(ani_env* env, ani_object aniC TAG_LOGD(AAFwkTag::UI_EXT, "NativeReportDrawnCompleted end"); } +void EtsUIExtensionContext::ConnectUIServiceExtension(ani_env *env, ani_object aniObj, ani_object wantObj, + ani_object uiServiceExtConCallbackObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::UI_EXT, "ConnectUIServiceExtension called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "null env"); + return; + } + auto etsUiExtensionContext = GetEtsUIExtensionContext(env, aniObj); + if (etsUiExtensionContext == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "null etsUiExtensionContext"); + return; + } + etsUiExtensionContext->OnConnectUIServiceExtension(env, wantObj, uiServiceExtConCallbackObj, callback); +} + +bool EtsUIExtensionContext::CheckConnectAlreadyExist(ani_env *env, const AAFwk::Want& want, ani_object callback, ani_object result) +{ + TAG_LOGI(AAFwkTag::UI_EXT, "CheckConnectAlreadyExist called"); + sptr connection = nullptr; + UIServiceConnection::FindUIServiceExtensionConnection(env, want, callback, connection); + if (connection == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "null connection"); + return false; + } + + std::unique_ptr uasyncTask = CreateAsyncTaskWithLastParam(env, nullptr, nullptr, nullptr, &result); + napi_value proxy = connection->GetProxyObject(); + if (proxy == nullptr) { + TAG_LOGW(AAFwkTag::UI_EXT, "null proxy"); + connection->AddDuplicatedPendingTask(uasyncTask); + } else { + TAG_LOGI(AAFwkTag::UI_EXT, "Resolve, got proxy object"); + uasyncTask->ResolveWithNoError(env, proxy); + } + return true; +} + +void EtsUIExtensionContext::OnConnectUIServiceExtension(ani_env *env, ani_object wantObj, + ani_object uiServiceExtConCallbackObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::UI_EXT, "OnConnectUIServiceExtension called"); + AAFwk::Want want; + if (!AppExecFwk::UnwrapWant(env, wantObj, want)) { + TAG_LOGE(AAFwkTag::UI_EXT, "input param want failed"); + EtsErrorUtil::ThrowInvalidParamError(env, "Parse param want failed, want must be Want."); + return; + } + + napi_value result = nullptr; + bool duplicated = CheckConnectAlreadyExist(env, want, callbackObject, result); + if (duplicated) { + TAG_LOGE(AAFwkTag::UI_EXT, "duplicated"); + return result; + } + + sptr connection = sptr::MakeSptr(env); + sptr stub = connection->GetServiceHostStub(); + want.SetParam(UISERVICEHOSTPROXY_KEY, stub->AsObject()); + + result = nullptr; + std::unique_ptr uasyncTask = CreateAsyncTaskWithLastParam(env, nullptr, nullptr, nullptr, &result); + std::shared_ptr uasyncTaskShared = std::move(uasyncTask); + if (info.argc > ARGC_ONE) { + connection->SetJsConnectionObject(callbackObject); + } + connection->SetNapiAsyncTask(uasyncTaskShared); + UIServiceConnection::AddUIServiceExtensionConnection(want, connection); + std::unique_ptr complete = std::make_unique( + [weak = context_, want, uasyncTaskShared, connection]( + napi_env env, NapiAsyncTask& taskUseless, int32_t status) { + DoConnectUIServiceExtension(env, weak, connection, uasyncTaskShared, want); + }); + napi_ref callback = nullptr; + std::unique_ptr execute = nullptr; + NapiAsyncTask::ScheduleHighQos("JsUIExtensionContext::OnConnectUIServiceExtension", + env, std::make_unique(callback, std::move(execute), std::move(complete))); + return result; +} + +void EtsUIExtensionContext::StartUIServiceExtension(ani_env *env, ani_object aniObj, + ani_object wantObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::UI_EXT, "StartUIServiceExtension called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "null env"); + return; + } + auto etsUiExtensionContext = GetEtsUIExtensionContext(env, aniObj); + if (etsUiExtensionContext == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "null etsUiExtensionContext"); + return; + } + etsUiExtensionContext->OnStartUIServiceExtension(env, wantObj, callback); +} + +void EtsUIExtensionContext::DisconnectUIServiceExtension(ani_env *env, ani_object aniObj, + ani_object proxyObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::UI_EXT, "StartUIServiceExtension called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "null env"); + return; + } + auto etsUiExtensionContext = GetEtsUIExtensionContext(env, aniObj); + if (etsUiExtensionContext == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "null etsUiExtensionContext"); + return; + } + etsUiExtensionContext->OnDisconnectUIServiceExtension(env, proxyObj, callback); +} + bool EtsUIExtensionContext::BindNativePtrCleaner(ani_env *env) { if (env == nullptr) { @@ -634,7 +746,19 @@ ani_object CreateEtsUIExtensionContext(ani_env *env, std::shared_ptr(EtsUIExtensionContext::SetColorMode)}, ani_native_function{"nativeReportDrawnCompleted", "Lutils/AbilityUtils/AsyncCallbackWrapper;:V", - reinterpret_cast(EtsUIExtensionContext::ReportDrawnCompleted)} + reinterpret_cast(EtsUIExtensionContext::ReportDrawnCompleted)}, + ani_native_function{"nativeConnectUIServiceExtensionAbility", + "L@ohos/app/ability/Want/Want;" + "Lapplication/UIServiceExtensionConnectCallback/UIServiceExtensionConnectCallbackImpl;" + "Lutils/AbilityUtils/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsUIExtensionContext::ConnectUIServiceExtensionAbility)}, + ani_native_function{"nativeStartUIServiceExtensionAbility", + "L@ohos/app/ability/Want/Want;Lutils/AbilityUtils/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsUIExtensionContext::StartUIServiceExtensionAbility)}, + ani_native_function{"nativeDisconnectUIServiceExtensionAbility", + "Lapplication/UIServiceProxy/UIServiceProxyImpl;" + "Lutils/AbilityUtils/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsUIExtensionContext::DisconnectUIServiceExtensionAbility)} }; if ((status = env->Class_BindNativeMethods(cls, functions.data(), functions.size())) != ANI_OK) { TAG_LOGE(AAFwkTag::UI_EXT, "status: %{public}d", status); diff --git a/frameworks/ets/ani/ui_extension_ability/src/ets_uiservice_uiext_connection.cpp b/frameworks/ets/ani/ui_extension_ability/src/ets_uiservice_uiext_connection.cpp new file mode 100644 index 00000000000..333ca6ae50a --- /dev/null +++ b/frameworks/ets/ani/ui_extension_ability/src/ets_uiservice_uiext_connection.cpp @@ -0,0 +1,259 @@ +/* + * 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 "js_uiservice_uiext_connection.h" + +#include "ability_business_error.h" +#include "hilog_tag_wrapper.h" +#include "js_error_utils.h" +#include "js_ui_service_proxy.h" +#include "napi_common_want.h" +#include "ui_extension_servicehost_stub_impl.h" + +namespace OHOS { +namespace AbilityRuntime { +constexpr size_t ARGC_ONE = 1; + +namespace UIServiceConnection { +static std::map, key_compare> gUiServiceExtConnects; +static std::recursive_mutex gUiServiceExtConnectsLock; +static int64_t gUiServiceExtConnectSn = 0; + +void AddUIServiceExtensionConnection(AAFwk::Want& want, sptr& connection) +{ + std::lock_guard lock(gUiServiceExtConnectsLock); + UIExtensionConnectionKey key; + key.id = gUiServiceExtConnectSn; + key.want = want; + connection->SetConnectionId(key.id); + gUiServiceExtConnects.emplace(key, connection); + if (gUiServiceExtConnectSn < INT32_MAX) { + gUiServiceExtConnectSn++; + } else { + gUiServiceExtConnectSn = 0; + } +} + +void RemoveUIServiceExtensionConnection(const int64_t& connectId) +{ + std::lock_guard lock(gUiServiceExtConnectsLock); + auto item = std::find_if(gUiServiceExtConnects.begin(), gUiServiceExtConnects.end(), + [&connectId](const auto &obj) { + return connectId == obj.first.id; + }); + if (item != gUiServiceExtConnects.end()) { + TAG_LOGI(AAFwkTag::UI_EXT, "found, erase"); + gUiServiceExtConnects.erase(item); + } else { + TAG_LOGI(AAFwkTag::UI_EXT, "not found"); + } + TAG_LOGI(AAFwkTag::UI_EXT, "connects new size:%{public}zu", gUiServiceExtConnects.size()); +} + +void FindUIServiceExtensionConnection(const int64_t& connectId, AAFwk::Want& want, + sptr& connection) +{ + std::lock_guard lock(gUiServiceExtConnectsLock); + TAG_LOGI(AAFwkTag::UI_EXT, "connection:%{public}d", static_cast(connectId)); + auto item = std::find_if(gUiServiceExtConnects.begin(), gUiServiceExtConnects.end(), + [&connectId](const auto &obj) { + return connectId == obj.first.id; + }); + if (item != gUiServiceExtConnects.end()) { + want = item->first.want; + connection = item->second; + TAG_LOGI(AAFwkTag::UI_EXT, "found"); + } else { + TAG_LOGI(AAFwkTag::UI_EXT, "not found"); + } +} + +void FindUIServiceExtensionConnection(napi_env env, AAFwk::Want& want, napi_value callback, + sptr& connection) +{ + std::lock_guard lock(gUiServiceExtConnectsLock); + auto item = std::find_if(gUiServiceExtConnects.begin(), gUiServiceExtConnects.end(), + [&want, env, callback](const auto &obj) { + bool wantEquals = (obj.first.want.GetElement() == want.GetElement()); + std::unique_ptr& tempCallbackPtr = obj.second->GetJsConnectionObject(); + bool callbackObjectEquals = + JSUIServiceUIExtConnection::IsJsCallbackObjectEquals(env, tempCallbackPtr, callback); + return wantEquals && callbackObjectEquals; + }); + if (item == gUiServiceExtConnects.end()) { + return; + } + connection = item->second; +} +} + +JSUIServiceUIExtConnection::JSUIServiceUIExtConnection(napi_env env) : JSUIExtensionConnection(env) +{ + TAG_LOGI(AAFwkTag::UISERVC_EXT, "JSUIServiceUIExtConnection"); + wptr weakthis = this; + serviceHostStub_ = sptr::MakeSptr(weakthis); +} + +JSUIServiceUIExtConnection::~JSUIServiceUIExtConnection() +{ + TAG_LOGI(AAFwkTag::UISERVC_EXT, "~JSUIServiceUIExtConnection"); + serviceHostStub_ = nullptr; + napiAsyncTask_.reset(); + ReleaseNativeReference(serviceProxyObject_.release()); +} + +void JSUIServiceUIExtConnection::HandleOnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + if (napiAsyncTask_ != nullptr) { + TAG_LOGI(AAFwkTag::UISERVC_EXT, "HandleOnAbilityConnectDone, CreateJsUIServiceProxy"); + sptr hostStub = GetServiceHostStub(); + sptr hostProxy = nullptr; + if (hostStub != nullptr) { + hostProxy = hostStub->AsObject(); + } + napi_value proxy = AAFwk::JsUIServiceProxy::CreateJsUIServiceProxy(env_, remoteObject, + connectionId_, hostProxy); + SetProxyObject(proxy); + napiAsyncTask_->ResolveWithNoError(env_, proxy); + + ResolveDuplicatedPendingTask(env_, proxy); + } else { + TAG_LOGE(AAFwkTag::UISERVC_EXT, "null napiAsyncTask_"); + } + napiAsyncTask_.reset(); +} + +void JSUIServiceUIExtConnection::HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element, + int resultCode) +{ + if (napiAsyncTask_ != nullptr) { + napi_value innerError = CreateJsError(env_, AbilityErrorCode::ERROR_CODE_INNER); + napiAsyncTask_->Reject(env_, innerError); + RejectDuplicatedPendingTask(env_, innerError); + napiAsyncTask_ = nullptr; + } + CallJsOnDisconnect(); + SetProxyObject(nullptr); + RemoveConnectionObject(); + duplicatedPendingTaskList_.clear(); + UIServiceConnection::RemoveUIServiceExtensionConnection(connectionId_); +} + +void JSUIServiceUIExtConnection::SetNapiAsyncTask(std::shared_ptr& task) +{ + napiAsyncTask_ = task; +} + +void JSUIServiceUIExtConnection::AddDuplicatedPendingTask(std::unique_ptr& task) +{ + duplicatedPendingTaskList_.push_back(std::move(task)); +} + +void JSUIServiceUIExtConnection::ResolveDuplicatedPendingTask(napi_env env, napi_value proxy) +{ + TAG_LOGI(AAFwkTag::UISERVC_EXT, "called, size %{public}zu", duplicatedPendingTaskList_.size()); + for (auto &task : duplicatedPendingTaskList_) { + if (task != nullptr) { + task->ResolveWithNoError(env, proxy); + } + } + duplicatedPendingTaskList_.clear(); +} + +void JSUIServiceUIExtConnection::RejectDuplicatedPendingTask(napi_env env, napi_value error) +{ + TAG_LOGI(AAFwkTag::UISERVC_EXT, "called, size %{public}zu", duplicatedPendingTaskList_.size()); + for (auto &task : duplicatedPendingTaskList_) { + if (task != nullptr) { + task->Reject(env, error); + } + } + duplicatedPendingTaskList_.clear(); +} + +void JSUIServiceUIExtConnection::SetProxyObject(napi_value proxy) +{ + TAG_LOGI(AAFwkTag::UISERVC_EXT, "SetProxyObject"); + serviceProxyObject_.reset(); + if (proxy != nullptr) { + napi_ref ref = nullptr; + napi_create_reference(env_, proxy, 1, &ref); + serviceProxyObject_ = std::unique_ptr(reinterpret_cast(ref)); + } +} + +napi_value JSUIServiceUIExtConnection::GetProxyObject() +{ + if (serviceProxyObject_ == nullptr) { + return nullptr; + } + return serviceProxyObject_->GetNapiValue(); +} + +int32_t JSUIServiceUIExtConnection::OnSendData(OHOS::AAFwk::WantParams &data) +{ + wptr connection = this; + std::unique_ptr complete = std::make_unique + ([connection, wantParams = data](napi_env env, NapiAsyncTask &task, int32_t status) { + sptr connectionSptr = connection.promote(); + if (!connectionSptr) { + TAG_LOGE(AAFwkTag::UISERVC_EXT, "null connectionSptr"); + return; + } + connectionSptr->HandleOnSendData(wantParams); + }); + + napi_ref callback = nullptr; + std::unique_ptr execute = nullptr; + NapiAsyncTask::Schedule("JSUIServiceUIExtConnection::SendData", + env_, std::make_unique(callback, std::move(execute), std::move(complete))); + + return static_cast(AbilityErrorCode::ERROR_OK); +} + +void JSUIServiceUIExtConnection::HandleOnSendData(const OHOS::AAFwk::WantParams &data) +{ + napi_value argv[] = { AppExecFwk::CreateJsWantParams(env_, data) }; + CallObjectMethod("onData", argv, ARGC_ONE); +} + +void JSUIServiceUIExtConnection::CallJsOnDisconnect() +{ + TAG_LOGI(AAFwkTag::UISERVC_EXT, "called"); + CallObjectMethod("onDisconnect", nullptr, 0); +} + +bool JSUIServiceUIExtConnection::IsJsCallbackObjectEquals(napi_env env, + std::unique_ptr &callback, napi_value value) +{ + if (value == nullptr || callback == nullptr) { + return callback.get() == reinterpret_cast(value); + } + auto object = callback->GetNapiValue(); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::UISERVC_EXT, "null object"); + return false; + } + bool result = false; + if (napi_strict_equals(env, object, value, &result) != napi_ok) { + TAG_LOGE(AAFwkTag::UISERVC_EXT, "object does not match value"); + return false; + } + return result; +} + +} +} diff --git a/frameworks/ets/ets/application/ServiceExtensionContext.ets b/frameworks/ets/ets/application/ServiceExtensionContext.ets index 569ada6a428..58296c0874a 100644 --- a/frameworks/ets/ets/application/ServiceExtensionContext.ets +++ b/frameworks/ets/ets/application/ServiceExtensionContext.ets @@ -72,6 +72,8 @@ export default class ServiceExtensionContext extends ExtensionContext { native nativeDisconnectServiceExtensionAbility(connection: long, callback: AsyncCallbackWrapper): void; + native nativeStartUIServiceExtensionAbility(want: Want, callback: AsyncCallbackWrapper): void; + terminateSelf(callback: AsyncCallback): void { let myCall = new AsyncCallbackWrapper(callback); taskpool.execute((): void => { @@ -192,4 +194,19 @@ export default class ServiceExtensionContext extends ExtensionContext { }) }); } + + startUIServiceExtensionAbility(want: Want): Promise { + return new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null) => { + if (err == null || err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeStartUIServiceExtensionAbility(want, myCall); + }); + }); + } } diff --git a/frameworks/ets/ets/application/UIAbilityContext.ets b/frameworks/ets/ets/application/UIAbilityContext.ets index fce9b28feff..6a24816c7ec 100644 --- a/frameworks/ets/ets/application/UIAbilityContext.ets +++ b/frameworks/ets/ets/application/UIAbilityContext.ets @@ -146,6 +146,10 @@ export default class UIAbilityContext extends Context { }); } + private native nativeConnectUIServiceExtensionAbility(want: Want, uiServiceExtConCallback: UIServiceExtensionConnectCallback, callback:AsyncCallbackWrapper): void; + private native nativeStartUIServiceExtensionAbility(want: Want, callback:AsyncCallbackWrapper): void; + private native nativeDisconnectUIServiceExtensionAbility(proxy: UIServiceProxy, callback:AsyncCallbackWrapper): void; + startAbility(want: Want, options: StartOptions, callback: AsyncCallback): void { let myCall = new AsyncCallbackWrapper(callback); taskpool.execute((): void => { @@ -452,7 +456,7 @@ export default class UIAbilityContext extends Context { callback(null, undefined); } else { callback(retError, undefined); - } + } }, (err: Error): void => { callback(err as BusinessError, undefined); }); @@ -527,7 +531,6 @@ hideAbility(): Promise { }); } - setAbilityInstanceInfo(label: string, icon: image.PixelMap): Promise { let p:Promise = new Promise((resolve: (data:undefined)=>void, reject: (err: BusinessError)=>void):void => { let syncCall = new AsyncCallbackWrapper((err: BusinessError | null)=>{ @@ -543,4 +546,50 @@ hideAbility(): Promise { }); return p; } + + connectUIServiceExtensionAbility(want: Want, callback: UIServiceExtensionConnectCallback) : Promise { + return new Promise((resolve: (data: UIServiceProxy) => void, + reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null, data: UIServiceProxy | undefined) => { + if (err == null || err.code == 0) { + resolve(data as UIServiceProxy); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeConnectUIServiceExtensionAbility(want, myCall); + }); + }); + } + + startUIServiceExtensionAbility(want: Want): Promise { + return new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null) => { + if (err == null || err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeStartUIServiceExtensionAbility(want, myCall); + }); + }); + } + + disconnectUIServiceExtensionAbility(proxy: UIServiceProxy): Promise { + return new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null) => { + if (err == null || err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeDisconnectUIServiceExtensionAbility(proxy, myCall); + }); + }); + } } diff --git a/frameworks/ets/ets/application/UIExtensionContext.ets b/frameworks/ets/ets/application/UIExtensionContext.ets index b7fb7e061ed..5b9fca69544 100644 --- a/frameworks/ets/ets/application/UIExtensionContext.ets +++ b/frameworks/ets/ets/application/UIExtensionContext.ets @@ -64,6 +64,9 @@ export default class UIExtensionContext extends ExtensionContext { callback:AsyncCallbackWrapper): void; native setColorMode(colorMode: ConfigurationConstant.ColorMode): void; native nativeReportDrawnCompleted(callback:AsyncCallbackWrapper): void; + private native nativeConnectUIServiceExtensionAbility(want: Want, uiServiceExtConCallback: UIServiceExtensionConnectCallback, callback:AsyncCallbackWrapper): void; + private native nativeStartUIServiceExtensionAbility(want: Want, callback:AsyncCallbackWrapper): void; + private native nativeDisconnectUIServiceExtensionAbility(proxy: UIServiceProxy, callback:AsyncCallbackWrapper): void; terminateSelf(callback:AsyncCallback): void { let myCall = new AsyncCallbackWrapper(callback); @@ -222,4 +225,52 @@ export default class UIExtensionContext extends ExtensionContext { this.nativeReportDrawnCompleted(myCall); }); } + + connectUIServiceExtensionAbility(want: Want, callback: UIServiceExtensionConnectCallback) : Promise { + return new Promise((resolve: (data: UIServiceProxy) => void, + reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null, data: UIServiceProxy | undefined) => { + if (err == null || err.code == 0) { + resolve(data as UIServiceProxy); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeConnectUIServiceExtensionAbility(want, callback, myCall); + }); + }); + } + + startUIServiceExtensionAbility(want: Want): Promise { + return new Promise((resolve: (data: void) => void, + reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null) => { + if (err == null || err.code == 0) { + resolve(); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeStartUIServiceExtensionAbility(want, myCall); + }); + }); + } + + disconnectUIServiceExtensionAbility(proxy: UIServiceProxy): Promise { + return new Promise((resolve: (data: void) => void, + reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError | null) => { + if (err == null || err.code == 0) { + resolve(); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeDisconnectUIServiceExtensionAbility(proxy, myCall); + }); + }); + } } \ No newline at end of file diff --git a/frameworks/ets/ets/application/UIServiceExtensionConnectCallback.ets b/frameworks/ets/ets/application/UIServiceExtensionConnectCallback.ets new file mode 100644 index 00000000000..ba3adf583d5 --- /dev/null +++ b/frameworks/ets/ets/application/UIServiceExtensionConnectCallback.ets @@ -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. + */ + +export default interface UIServiceExtensionConnectCallback { + onData(data: Record): void; + onDisconnect(): void; +} + +export class UIServiceExtensionConnectCallbackImpl implements UIServiceExtensionConnectCallback { + onData(data: Record): void {} + onDisconnect(): void {} +} \ No newline at end of file -- Gitee