From 60a66e221b54451a2617b46d46bbd7cfe8a081e2 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Thu, 7 Aug 2025 14:59:09 +0800 Subject: [PATCH] add auto_fill_extension Signed-off-by: zhangzezhong --- .../include/ets_auto_fill_extension_context.h | 43 +++ .../include/ets_auto_fill_extension_util.h | 71 ++++ .../include/ets_fill_request_callback.h | 56 +++ .../include/ets_save_request_callback.h | 50 +++ .../src/ets_auto_fill_extension_context.cpp | 212 ++++++++++ .../src/ets_auto_fill_extension_util.cpp | 236 ++++++++++++ .../src/ets_fill_request_callback.cpp | 362 ++++++++++++++++++ .../src/ets_save_request_callback.cpp | 228 +++++++++++ frameworks/ets/ets/BUILD.gn | 102 +++++ .../application/AutoFillExtensionContext.ets | 72 ++++ .../ets/application/AutoFillPopupConfig.ets | 47 +++ .../ets/ets/application/AutoFillRect.ets | 28 ++ .../ets/ets/application/AutoFillRequest.ets | 120 ++++++ .../ets/ets/application/PageNodeInfo.ets | 45 +++ frameworks/ets/ets/application/ViewData.ets | 39 ++ frameworks/native/ability/native/BUILD.gn | 52 +++ 16 files changed, 1763 insertions(+) create mode 100644 frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_context.h create mode 100644 frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_util.h create mode 100644 frameworks/ets/ani/auto_fill_extension_ability/include/ets_fill_request_callback.h create mode 100644 frameworks/ets/ani/auto_fill_extension_ability/include/ets_save_request_callback.h create mode 100644 frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_context.cpp create mode 100644 frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_util.cpp create mode 100644 frameworks/ets/ani/auto_fill_extension_ability/src/ets_fill_request_callback.cpp create mode 100644 frameworks/ets/ani/auto_fill_extension_ability/src/ets_save_request_callback.cpp create mode 100644 frameworks/ets/ets/application/AutoFillExtensionContext.ets create mode 100644 frameworks/ets/ets/application/AutoFillPopupConfig.ets create mode 100644 frameworks/ets/ets/application/AutoFillRect.ets create mode 100644 frameworks/ets/ets/application/AutoFillRequest.ets create mode 100644 frameworks/ets/ets/application/PageNodeInfo.ets create mode 100644 frameworks/ets/ets/application/ViewData.ets diff --git a/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_context.h b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_context.h new file mode 100644 index 00000000000..3ce4d9da6c8 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_context.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 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_ETS_AUTO_FILL_EXTENSION_CONTEXT_H +#define OHOS_ABILITY_RUNTIME_ETS_AUTO_FILL_EXTENSION_CONTEXT_H + +#include "auto_fill_extension_context.h" + +namespace OHOS { +namespace AbilityRuntime { +class EtsAutoFillExtensionContext final { +public: + explicit EtsAutoFillExtensionContext(const std::shared_ptr &context) + : context_(context) {} + virtual ~EtsAutoFillExtensionContext() = default; + + static ani_object SetEtsAutoFillExtensionContext(ani_env *env, + const std::shared_ptr &context); + static EtsAutoFillExtensionContext *GetEtsAutoFillExtensionContext(ani_env *env, ani_object object); + static void Clean(ani_env *env, ani_object object); + static void ReloadInModal(ani_env *env, ani_object object, ani_object customDataObj, ani_object callback); + static ani_object CreateEtsAutoFillExtensionContext(ani_env *env, + const std::shared_ptr &context); + +private: + void OnReloadInModal(ani_env *env, ani_object object, ani_object customDataObj, ani_object callback); + std::weak_ptr context_; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_AUTO_FILL_EXTENSION_CONTEXT_H \ No newline at end of file diff --git a/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_util.h b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_util.h new file mode 100644 index 00000000000..8b3b9ff779a --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_util.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 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_ETS_AUTO_FILL_EXTENSION_UTIL_H +#define OHOS_ABILITY_RUNTIME_ETS_AUTO_FILL_EXTENSION_UTIL_H + +#include "ani.h" +#include "view_data.h" +#include "want.h" + +namespace OHOS { +namespace AbilityRuntime { +struct FillResponse { + AbilityBase::ViewData viewData; +}; + +struct PopupSize { + int32_t width = 0; + int32_t height = 0; +}; + +enum AutoFillCommand { + NONE, + FILL, + SAVE, + UPDATE, + RESIZE, + INPUT, + RELOAD_IN_MODAL +}; + +struct CustomData { + AAFwk::WantParams data; +}; + +class EtsAutoFillExtensionUtil { +public: + static void UnwrapViewData(ani_env *env, const ani_object object, AbilityBase::ViewData &viewData); + static void UnwrapPageNodeInfo(ani_env *env, const ani_object object, AbilityBase::PageNodeInfo &node); + static void UnwrapRectData(ani_env *env, const ani_object object, AbilityBase::Rect &rect); + static void UnwrapFillResponse(ani_env *env, const ani_object object, FillResponse &response); + static void UnwrapPopupSize(ani_env *env, const ani_object object, PopupSize &popupSize); + + enum AutoFillResultCode { + CALLBACK_SUCESS = 0, + CALLBACK_FAILED, + CALLBACK_CANCEL, + CALLBACK_REMOVE_TIME_OUT, + CALLBACK_FAILED_INVALID_PARAM, + }; + +private: + static void UnwrapViewDataString(ani_env *env, const ani_object object, AbilityBase::ViewData &viewData); + static void UnwrapViewDataBoolean(ani_env *env, const ani_object object, AbilityBase::ViewData &viewData); + static void UnwrapPageNodeInfoString(ani_env *env, const ani_object object, AbilityBase::PageNodeInfo &node); +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_AUTO_FILL_EXTENSION_UTIL_H \ No newline at end of file diff --git a/frameworks/ets/ani/auto_fill_extension_ability/include/ets_fill_request_callback.h b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_fill_request_callback.h new file mode 100644 index 00000000000..5777ae2c42e --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_fill_request_callback.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 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_ETS_FILL_REQUEST_CALLBACK_H +#define OHOS_ABILITY_RUNTIME_ETS_FILL_REQUEST_CALLBACK_H + +#include "ets_auto_fill_extension_util.h" +#include "session_info.h" +#include "want.h" +#include "window.h" + +namespace OHOS { +namespace AbilityRuntime { +class EtsFillRequestCallback { +public: + EtsFillRequestCallback(const sptr &sessionInfo, const sptr &uiWindow); + virtual ~EtsFillRequestCallback() = default; + + static ani_object SetEtsFillRequestCallback(ani_env *env, const sptr &sessionInfo, + const sptr &uiWindow); + static EtsFillRequestCallback *GetEtsFillRequestCallback(ani_env *env, ani_object object); + static void Clean(ani_env *env, ani_object object); + static ani_object CreateEtsFillRequestCallback(ani_env *env, const sptr &sessionInfo, + const sptr &uiWindow); + static void FillRequestSuccess(ani_env *env, ani_object object, ani_object responseObj); + static void FillRequestFailed(ani_env *env, ani_object object); + static void FillRequestCanceled(ani_env *env, ani_object object, ani_object fillContentObj); + static void FillRequestAutoFillPopupConfig(ani_env *env, ani_object object, ani_object autoFillPopupConfigObj); + +private: + void OnFillRequestSuccess(ani_env *env, ani_object object, ani_object responseObj); + void OnFillRequestFailed(ani_env *env, ani_object object); + void OnFillRequestCanceled(ani_env *env, ani_object object, ani_object fillContentObj); + void OnFillRequestAutoFillPopupConfig(ani_env *env, ani_object object, ani_object autoFillPopupConfigObj); + bool SetPopupConfigToWantParams(ani_env *env, ani_object autoFillPopupConfigObj, AAFwk::WantParams& wantParams); + void SendResultCodeAndViewData(const EtsAutoFillExtensionUtil::AutoFillResultCode &resultCode, + const std::string &etsString); + + sptr sessionInfo_; + sptr uiWindow_; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_FILL_REQUEST_CALLBACK_H \ No newline at end of file diff --git a/frameworks/ets/ani/auto_fill_extension_ability/include/ets_save_request_callback.h b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_save_request_callback.h new file mode 100644 index 00000000000..acabfbb7494 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_save_request_callback.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 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_ETS_SAVE_REQUEST_CALLBACK_H +#define OHOS_ABILITY_RUNTIME_ETS_SAVE_REQUEST_CALLBACK_H + +#include "ets_auto_fill_extension_util.h" +#include "session_info.h" +#include "want.h" +#include "window.h" + +namespace OHOS { +namespace AbilityRuntime { +class EtsSaveRequestCallback { +public: + EtsSaveRequestCallback(const sptr &sessionInfo, const sptr &uiWindow); + virtual ~EtsSaveRequestCallback() = default; + + static ani_object SetEtsSaveRequestCallback(ani_env *env, const sptr &sessionInfo, + const sptr &uiWindow); + static EtsSaveRequestCallback *GetEtsSaveRequestCallback(ani_env *env, ani_object object); + static void Clean(ani_env *env, ani_object object); + static ani_object CreateEtsSaveRequestCallback(ani_env *env, const sptr &sessionInfo, + const sptr &uiWindow); + static void SaveRequestSuccess(ani_env *env, ani_object object); + static void SaveRequestFailed(ani_env *env, ani_object object); + +private: + void OnSaveRequestSuccess(ani_env *env, ani_object object); + void OnSaveRequestFailed(ani_env *env, ani_object object); + void SendResultCodeAndViewData(const EtsAutoFillExtensionUtil::AutoFillResultCode &resultCode); + + sptr sessionInfo_; + sptr uiWindow_; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_SAVE_REQUEST_CALLBACK_H \ No newline at end of file diff --git a/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_context.cpp b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_context.cpp new file mode 100644 index 00000000000..1ac9d413557 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_context.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2025 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 "ets_auto_fill_extension_context.h" + +#include "ani_common_util.h" +#include "ani_common_want.h" +#include "ets_auto_fill_extension_util.h" +#include "ets_context_utils.h" +#include "ets_error_utils.h" +#include "ets_extension_context.h" +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char* AUTO_FILL_EXTENSION_CONTEXT_CLASS_NAME = + "Lapplication/AutoFillExtensionContext/AutoFillExtensionContext;"; +constexpr const char* CLEANER_CLASS = "Lapplication/AutoFillExtensionContext/Cleaner;"; +} + +ani_object EtsAutoFillExtensionContext::SetEtsAutoFillExtensionContext(ani_env *env, + const std::shared_ptr &context) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "SetEtsAutoFillExtensionContext Call"); + if (env == nullptr || context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env or context"); + return nullptr; + } + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass(AUTO_FILL_EXTENSION_CONTEXT_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find class status: %{public}d", status); + return nullptr; + } + ani_method method = nullptr; + if ((status = env->Class_FindMethod(cls, "", "J:V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find method status: %{public}d", status); + return nullptr; + } + auto etsAutoFillExtensionContext = new (std::nothrow) EtsAutoFillExtensionContext(context); + if (etsAutoFillExtensionContext == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "etsAutoFillExtensionContext nullptr"); + return nullptr; + } + ani_object contextObj = nullptr; + if ((status = env->Object_New(cls, method, &contextObj, reinterpret_cast(etsAutoFillExtensionContext))) + != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "new object status: %{public}d", status); + delete etsAutoFillExtensionContext; + etsAutoFillExtensionContext = nullptr; + return nullptr; + } + auto workContext = new (std::nothrow) std::weak_ptr( + etsAutoFillExtensionContext->context_); + if (workContext == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "workContext nullptr"); + return nullptr; + } + if (!ContextUtil::SetNativeContextLong(env, contextObj, reinterpret_cast(workContext))) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "SetNativeContextLong failed"); + delete workContext; + workContext = nullptr; + return nullptr; + } + return contextObj; +} + +EtsAutoFillExtensionContext *EtsAutoFillExtensionContext::GetEtsAutoFillExtensionContext(ani_env *env, + ani_object object) +{ + if (env == nullptr || object == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env or object"); + return nullptr; + } + ani_long autoFillExtensionContextPtr = 0; + ani_status status = env->Object_GetFieldByName_Long(object, "autoFillExtensionContextPtr", + &autoFillExtensionContextPtr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "autoFillExtensionContextPtr GetField status: %{public}d", status); + return nullptr; + } + auto etsAutoFillExtensionContext = reinterpret_cast(autoFillExtensionContextPtr); + if (etsAutoFillExtensionContext == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "etsAutoFillExtensionContext null"); + return nullptr; + } + return etsAutoFillExtensionContext; +} + +void EtsAutoFillExtensionContext::Clean(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Clean called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_long ptr = 0; + ani_status status = env->Object_GetFieldByName_Long(object, "ptr", &ptr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "ptr GetField status: %{public}d", status); + return; + } + if (ptr != 0) { + delete reinterpret_cast(ptr); + } +} + +void EtsAutoFillExtensionContext::ReloadInModal(ani_env *env, ani_object object, ani_object customDataObj, + ani_object callback) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "ReloadInModal called"); + auto etsAutoFillExtensionContext = GetEtsAutoFillExtensionContext(env, object); + if (etsAutoFillExtensionContext == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsAutoFillExtensionContext"); + return; + } + etsAutoFillExtensionContext->OnReloadInModal(env, object, customDataObj, callback); +} + +void EtsAutoFillExtensionContext::OnReloadInModal(ani_env *env, ani_object object, ani_object customDataObj, + ani_object callback) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_ref etsCustomData = nullptr; + if (!AppExecFwk::GetFieldRefByName(env, customDataObj, "data", etsCustomData)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "get data failed"); + return; + } + CustomData customData; + if (etsCustomData == nullptr || !AppExecFwk::UnwrapWantParams(env, etsCustomData, customData.data)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Parse custom data failed"); + AbilityRuntime::EtsErrorUtil::ThrowError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + return; + } + auto context = context_.lock(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null context"); + AbilityRuntime::EtsErrorUtil::ThrowError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT); + return; + } + auto ret = context->ReloadInModal(customData); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "error is %{public}d", ret); + } + AppExecFwk::AsyncCallback(env, callback, + AbilityRuntime::EtsErrorUtil::CreateErrorByNativeErr(env, static_cast(ret)), nullptr); +} + +ani_object EtsAutoFillExtensionContext::CreateEtsAutoFillExtensionContext(ani_env *env, + const std::shared_ptr &context) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr || context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env or context"); + return nullptr; + } + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass(AUTO_FILL_EXTENSION_CONTEXT_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find class status: %{public}d", status); + return nullptr; + } + std::array functions = { + ani_native_function { "nativeReloadInModal", + "Lapplication/CustomData/CustomData;Lutils/AbilityUtils/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAutoFillExtensionContext::ReloadInModal) }, + }; + if ((status = env->Class_BindNativeMethods(cls, functions.data(), functions.size())) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "bind method status : %{public}d", status); + return nullptr; + } + ani_class cleanerCls = nullptr; + if ((status = env->FindClass(CLEANER_CLASS, &cleanerCls)) != ANI_OK || cleanerCls == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Cleaner FindClass failed status: %{public}d, or null cleanerCls", status); + return nullptr; + } + std::array cleanerMethods = { + ani_native_function {"clean", nullptr, reinterpret_cast(EtsAutoFillExtensionContext::Clean) }, + }; + if ((status = env->Class_BindNativeMethods(cleanerCls, cleanerMethods.data(), cleanerMethods.size())) != + ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "cleanerCls Class_BindNativeMethods failed status: %{public}d", status); + return nullptr; + } + ani_object contextObj = SetEtsAutoFillExtensionContext(env, context); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null contextObj"); + return nullptr; + } + AbilityRuntime::ContextUtil::CreateEtsBaseContext(env, cls, contextObj, context); + AbilityRuntime::CreateEtsExtensionContext(env, cls, contextObj, context, context->GetAbilityInfo()); + return contextObj; +} +} +} \ No newline at end of file diff --git a/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_util.cpp b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_util.cpp new file mode 100644 index 00000000000..fec61358431 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_util.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2025 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 "ets_auto_fill_extension_util.h" + +#include "ani_common_util.h" +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *VIEW_DATA_BUNDLE_NAME = "bundleName"; +constexpr const char *VIEW_DATA_MODULE_NAME = "moduleName"; +constexpr const char *VIEW_DATA_ABILITY_NAME = "abilityName"; +constexpr const char *VIEW_DATA_PAGEURL = "pageUrl"; +constexpr const char *VIEW_DATA_USER_SELECTED = "isUserSelected"; +constexpr const char *VIEW_DATA_OTHER_ACCOUNT = "isOtherAccount"; +constexpr const char *VIEW_DATA_PAGE_NODE_INFOS = "pageNodeInfos"; +constexpr const char *VIEW_DATA_VIEW_DATA = "viewData"; +constexpr const char *VIEW_DATA_PAGE_RECT = "pageRect"; +constexpr const char *PAGE_INFO_ID = "id"; +constexpr const char *PAGE_INFO_DEPTH = "depth"; +constexpr const char *PAGE_INFO_AUTOFILLTYPE = "autoFillType"; +constexpr const char *PAGE_INFO_TAG = "tag"; +constexpr const char *PAGE_INFO_VALUE = "value"; +constexpr const char *PAGE_INFO_PLACEHOLDER = "placeholder"; +constexpr const char *PAGE_INFO_META_DATA = "metadata"; +constexpr const char *PAGE_INFO_PASSWORDRULES = "passwordRules"; +constexpr const char *PAGE_INFO_ENABLEAUTOFILL = "enableAutoFill"; +constexpr const char *PAGE_INFO_IS_FOCUS = "isFocus"; +constexpr const char *PAGE_INFO_PAGE_NODE_RECT = "rect"; +constexpr const char *RECT_POSITION_LEFT = "left"; +constexpr const char *RECT_POSITION_TOP = "top"; +constexpr const char *RECT_WIDTH = "width"; +constexpr const char *RECT_HEIGHT = "height"; +constexpr uint32_t PAGE_NODE_COUNT_MAX = 100; +} // namespace + +void EtsAutoFillExtensionUtil::UnwrapViewData(ani_env *env, const ani_object object, AbilityBase::ViewData &viewData) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + ani_ref etsViewData = nullptr; + if (!AppExecFwk::GetFieldRefByName(env, object, VIEW_DATA_VIEW_DATA, etsViewData)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "GetFieldRefByName failed"); + return; + } + if (etsViewData == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsViewData"); + return; + } + UnwrapViewDataString(env, static_cast(etsViewData), viewData); + UnwrapViewDataBoolean(env, static_cast(etsViewData), viewData); + ani_ref etsPageNodeInfos = nullptr; + if (!AppExecFwk::GetFieldRefByName(env, static_cast(etsViewData), VIEW_DATA_PAGE_NODE_INFOS, + etsPageNodeInfos)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "GetFieldRefByName failed"); + return; + } + if (etsPageNodeInfos != nullptr) { + ani_status status = ANI_ERROR; + ani_double etsProCount = 0.0; + if ((status = env->Object_GetPropertyByName_Double(static_cast(etsPageNodeInfos), "length", + &etsProCount)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_GetPropertyByName_Double failed, status: %{public}d", status); + return; + } + for (uint32_t index = 0; index < static_cast(etsProCount) && index < PAGE_NODE_COUNT_MAX; index++) { + ani_ref etsNode = nullptr; + if ((status = env->Object_CallMethodByName_Ref(static_cast(etsPageNodeInfos), "$_get", + "I:Lstd/core/Object;", &etsNode, (ani_int)index)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_CallMethodByName_Ref failed, status: %{public}d", status); + return; + } + AbilityBase::PageNodeInfo node; + UnwrapPageNodeInfo(env, static_cast(etsNode), node); + viewData.nodes.emplace_back(node); + } + } + ani_ref etsPageRect = nullptr; + if (!AppExecFwk::GetFieldRefByName(env, static_cast(etsViewData), VIEW_DATA_PAGE_RECT, etsPageRect)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "GetFieldRefByName failed"); + return; + } + if (etsPageRect != nullptr) { + UnwrapRectData(env, static_cast(etsPageRect), viewData.pageRect); + } +} + +void EtsAutoFillExtensionUtil::UnwrapPageNodeInfo(ani_env *env, const ani_object object, + AbilityBase::PageNodeInfo &node) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + ani_int id = 0; + if (AppExecFwk::GetFieldIntByName(env, object, PAGE_INFO_ID, id)) { + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "id:%{public}d", id); + node.id = id; + } + ani_int depth = 0; + if (AppExecFwk::GetFieldIntByName(env, object, PAGE_INFO_DEPTH, depth)) { + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "id:%{public}d", depth); + node.depth = depth; + } + ani_double autoFillType = 0.0; + if (AppExecFwk::GetFieldDoubleByName(env, object, PAGE_INFO_AUTOFILLTYPE, autoFillType)) { + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "id:%{public}f", autoFillType); + node.autoFillType = static_cast(autoFillType); + } + UnwrapPageNodeInfoString(env, object, node); + bool enableAutoFill = false; + if (AppExecFwk::GetFieldBoolByName(env, object, PAGE_INFO_ENABLEAUTOFILL, enableAutoFill)) { + node.enableAutoFill = enableAutoFill; + } + ani_ref etsRect = nullptr; + if (!AppExecFwk::GetFieldRefByName(env, object, PAGE_INFO_PAGE_NODE_RECT, etsRect)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "GetFieldRefByName failed"); + return; + } + if (etsRect != nullptr) { + UnwrapRectData(env, static_cast(etsRect), node.rect); + } + bool isFocus = false; + if (AppExecFwk::GetFieldBoolByName(env, object, PAGE_INFO_IS_FOCUS, isFocus)) { + node.isFocus = isFocus; + } +} + +void EtsAutoFillExtensionUtil::UnwrapRectData(ani_env *env, const ani_object object, AbilityBase::Rect &rect) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + ani_double position = 0.0; + if (AppExecFwk::GetFieldDoubleByName(env, object, RECT_POSITION_LEFT, position)) { + rect.left = position; + } + if (AppExecFwk::GetFieldDoubleByName(env, object, RECT_POSITION_TOP, position)) { + rect.top = position; + } + if (AppExecFwk::GetFieldDoubleByName(env, object, RECT_WIDTH, position)) { + rect.width = position; + } + if (AppExecFwk::GetFieldDoubleByName(env, object, RECT_HEIGHT, position)) { + rect.height = position; + } +} + +void EtsAutoFillExtensionUtil::UnwrapFillResponse(ani_env *env, const ani_object object, FillResponse &response) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + UnwrapViewData(env, object, response.viewData); +} + +void EtsAutoFillExtensionUtil::UnwrapPopupSize(ani_env *env, const ani_object object, PopupSize &popupSize) +{ + ani_double width = 0.0; + if (AppExecFwk::GetFieldDoubleByName(env, object, RECT_WIDTH, width)) { + popupSize.width = width; + } + ani_double height = 0.0; + if (AppExecFwk::GetFieldDoubleByName(env, object, RECT_HEIGHT, height)) { + popupSize.height = height; + } +} + +void EtsAutoFillExtensionUtil::UnwrapViewDataString(ani_env *env, const ani_object object, + AbilityBase::ViewData &viewData) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + std::string bundleName = ""; + if (AppExecFwk::GetFieldStringByName(env, object, VIEW_DATA_BUNDLE_NAME, bundleName)) { + viewData.bundleName = bundleName; + } + std::string moduleName = ""; + if (AppExecFwk::GetFieldStringByName(env, object, VIEW_DATA_MODULE_NAME, moduleName)) { + viewData.moduleName = moduleName; + } + std::string abilityName = ""; + if (AppExecFwk::GetFieldStringByName(env, object, VIEW_DATA_ABILITY_NAME, abilityName)) { + viewData.abilityName = abilityName; + } + std::string pageUrl = ""; + if (AppExecFwk::GetFieldStringByName(env, object, VIEW_DATA_PAGEURL, pageUrl)) { + viewData.pageUrl = pageUrl; + } +} + +void EtsAutoFillExtensionUtil::UnwrapViewDataBoolean(ani_env *env, const ani_object object, + AbilityBase::ViewData &viewData) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + bool isUserSelected = false; + if (AppExecFwk::GetFieldBoolByName(env, object, VIEW_DATA_USER_SELECTED, isUserSelected)) { + viewData.isUserSelected = isUserSelected; + } + bool isOtherAccount = false; + if (AppExecFwk::GetFieldBoolByName(env, object, VIEW_DATA_OTHER_ACCOUNT, isOtherAccount)) { + viewData.isOtherAccount = isOtherAccount; + } +} + +void EtsAutoFillExtensionUtil::UnwrapPageNodeInfoString(ani_env *env, const ani_object object, + AbilityBase::PageNodeInfo &node) +{ + std::string tag = ""; + if (AppExecFwk::GetFieldStringByName(env, object, PAGE_INFO_TAG, tag)) { + node.tag = tag; + } + std::string value = ""; + if (AppExecFwk::GetFieldStringByName(env, object, PAGE_INFO_VALUE, value)) { + node.value = value; + } + std::string passwordRules = ""; + if (AppExecFwk::GetFieldStringByName(env, object, PAGE_INFO_PASSWORDRULES, passwordRules)) { + node.passwordRules = passwordRules; + } + std::string placeholder = ""; + if (AppExecFwk::GetFieldStringByName(env, object, PAGE_INFO_PLACEHOLDER, placeholder)) { + node.placeholder = placeholder; + } + std::string metadata = ""; + if (AppExecFwk::GetFieldStringByName(env, object, PAGE_INFO_META_DATA, metadata)) { + node.metadata = metadata; + } +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/auto_fill_extension_ability/src/ets_fill_request_callback.cpp b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_fill_request_callback.cpp new file mode 100644 index 00000000000..3090c622af3 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_fill_request_callback.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2025 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 "ets_fill_request_callback.h" + +#include "ability_manager_client.h" +#include "ani_common_util.h" +#include "ets_error_utils.h" +#include "hilog_tag_wrapper.h" +#include "int_wrapper.h" +#include "ipc_skeleton.h" +#include "tokenid_kit.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *WANT_PARAMS_VIEW_DATA = "ohos.ability.params.viewData"; +constexpr const char *WANT_PARAMS_AUTO_FILL_CMD = "ohos.ability.params.autoFillCmd"; +constexpr const char *WANT_PARAMS_AUTO_FILL_CMD_AUTOFILL = "autofill"; +constexpr const char *WANT_PARAMS_UPDATE_POPUP_WIDTH = "ohos.ability.params.popupWidth"; +constexpr const char *WANT_PARAMS_UPDATE_POPUP_HEIGHT = "ohos.ability.params.popupHeight"; +constexpr const char *WANT_PARAMS_UPDATE_POPUP_PLACEMENT = "ohos.ability.params.popupPlacement"; +constexpr const char *CONFIG_POPUP_SIZE = "popupSize"; +constexpr const char *CONFIG_POPUP_PLACEMENT = "placement"; +constexpr const char *WANT_PARAMS_FILL_CONTENT = "ohos.ability.params.fillContent"; +constexpr const char *ERROR_MSG_INVALID_EMPTY = "JsonString is empty."; +constexpr const char *FILL_REQUEST_CALL_BACK_CLASS_NAME = "Lapplication/AutoFillRequest/FillRequestCallbackInner;"; +constexpr const char *CLEANER_CLASS = "Lapplication/AutoFillRequest/Cleaner;"; +} + +EtsFillRequestCallback::EtsFillRequestCallback( + const sptr &sessionInfo, const sptr &uiWindow) + : sessionInfo_(sessionInfo), uiWindow_(uiWindow) +{} + +ani_object EtsFillRequestCallback::SetEtsFillRequestCallback(ani_env *env, const sptr &sessionInfo, + const sptr &uiWindow) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "SetEtsFillRequestCallback Call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return nullptr; + } + if (sessionInfo == nullptr || uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo or uiWindow"); + return nullptr; + } + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass(FILL_REQUEST_CALL_BACK_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find class status: %{public}d", status); + return nullptr; + } + ani_method method = nullptr; + if ((status = env->Class_FindMethod(cls, "", "J:V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find method status: %{public}d", status); + return nullptr; + } + auto etsFillRequestCallback = new (std::nothrow) EtsFillRequestCallback(sessionInfo, uiWindow); + if (etsFillRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "etsFillRequestCallback nullptr"); + return nullptr; + } + ani_object contextObj = nullptr; + if ((status = env->Object_New(cls, method, &contextObj, reinterpret_cast(etsFillRequestCallback))) + != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "new object status: %{public}d", status); + delete etsFillRequestCallback; + etsFillRequestCallback = nullptr; + return nullptr; + } + return contextObj; +} + +EtsFillRequestCallback *EtsFillRequestCallback::GetEtsFillRequestCallback(ani_env *env, ani_object object) +{ + if (env == nullptr || object == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env or object"); + return nullptr; + } + ani_long fillRequestCallbackInnerPtr = 0; + ani_status status = env->Object_GetFieldByName_Long(object, "fillRequestCallbackInnerPtr", + &fillRequestCallbackInnerPtr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "fillRequestCallbackInnerPtr GetField status: %{public}d", status); + return nullptr; + } + auto etsFillRequestCallback = reinterpret_cast(fillRequestCallbackInnerPtr); + if (etsFillRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "etsFillRequestCallback null"); + return nullptr; + } + return etsFillRequestCallback; +} + +void EtsFillRequestCallback::Clean(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Clean called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_long ptr = 0; + ani_status status = env->Object_GetFieldByName_Long(object, "ptr", &ptr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "ptr GetField status: %{public}d", status); + return; + } + if (ptr != 0) { + delete reinterpret_cast(ptr); + } +} + +void EtsFillRequestCallback::FillRequestSuccess(ani_env *env, ani_object object, ani_object responseObj) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "FillRequestSuccess called"); + auto etsFillRequestCallback = GetEtsFillRequestCallback(env, object); + if (etsFillRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsFillRequestCallback"); + return; + } + etsFillRequestCallback->OnFillRequestSuccess(env, object, responseObj); +} + +void EtsFillRequestCallback::FillRequestFailed(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "FillRequestFailed called"); + auto etsFillRequestCallback = GetEtsFillRequestCallback(env, object); + if (etsFillRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsFillRequestCallback"); + return; + } + etsFillRequestCallback->OnFillRequestFailed(env, object); +} + +void EtsFillRequestCallback::FillRequestCanceled(ani_env *env, ani_object object, ani_object fillContentObj) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "FillRequestCanceled called"); + auto etsFillRequestCallback = GetEtsFillRequestCallback(env, object); + if (etsFillRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsFillRequestCallback"); + return; + } + etsFillRequestCallback->OnFillRequestCanceled(env, object, fillContentObj); +} + +void EtsFillRequestCallback::FillRequestAutoFillPopupConfig(ani_env *env, ani_object object, + ani_object autoFillPopupConfigObj) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "FillRequestAutoFillPopupConfig called"); + auto etsFillRequestCallback = GetEtsFillRequestCallback(env, object); + if (etsFillRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsFillRequestCallback"); + return; + } + etsFillRequestCallback->OnFillRequestAutoFillPopupConfig(env, object, autoFillPopupConfigObj); +} + +void EtsFillRequestCallback::OnFillRequestSuccess(ani_env *env, ani_object object, ani_object responseObj) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + FillResponse response; + EtsAutoFillExtensionUtil::UnwrapFillResponse(env, responseObj, response); + std::string jsonString = response.viewData.ToJsonString(); + if (jsonString.empty()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty jsonString"); + EtsErrorUtil::ThrowError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED_INVALID_PARAM, ""); + return; + } + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_SUCESS, jsonString); +} + +void EtsFillRequestCallback::OnFillRequestFailed(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED, ""); +} + +void EtsFillRequestCallback::OnFillRequestCanceled(ani_env *env, ani_object object, ani_object fillContentObj) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + std::string jsonString = ""; + ani_status status = ANI_OK; + ani_boolean isFillContentUndefined; + if ((status = env->Reference_IsUndefined(fillContentObj, &isFillContentUndefined)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Falied to check undefinde status: %{public}d", status); + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED_INVALID_PARAM, ""); + return; + } + if (!isFillContentUndefined) { + if (!AppExecFwk::GetStdString(env, reinterpret_cast(fillContentObj), jsonString)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty jsonString"); + EtsErrorUtil::ThrowError(env, static_cast(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), + ERROR_MSG_INVALID_EMPTY); + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED_INVALID_PARAM, ""); + return; + } + } + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_CANCEL, jsonString); +} + +void EtsFillRequestCallback::OnFillRequestAutoFillPopupConfig(ani_env *env, ani_object object, + ani_object autoFillPopupConfigObj) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + auto selfToken = IPCSkeleton::GetSelfTokenID(); + if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Non-system app forbidden to call"); + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP); + return; + } + if (uiWindow_ == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow"); + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER); + return; + } + AAFwk::WantParams wantParams; + wantParams.SetParam(WANT_PARAMS_AUTO_FILL_CMD, AAFwk::Integer::Box(AutoFillCommand::RESIZE)); + auto isValueChanged = SetPopupConfigToWantParams(env, autoFillPopupConfigObj, wantParams); + if (isValueChanged) { + auto ret = uiWindow_->TransferExtensionData(wantParams); + if (ret != Rosen::WMError::WM_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Transfer ability result failed"); + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER); + } + } +} + +bool EtsFillRequestCallback::SetPopupConfigToWantParams(ani_env *env, ani_object autoFillPopupConfigObj, + AAFwk::WantParams& wantParams) +{ + ani_ref etsValue = nullptr; + bool isValueChanged = false; + if (AppExecFwk::GetFieldRefByName(env, autoFillPopupConfigObj, CONFIG_POPUP_SIZE, etsValue) && etsValue) { + PopupSize popupSize; + EtsAutoFillExtensionUtil::UnwrapPopupSize(env, static_cast(etsValue), popupSize); + wantParams.SetParam(WANT_PARAMS_UPDATE_POPUP_WIDTH, AAFwk::Integer::Box(popupSize.width)); + wantParams.SetParam(WANT_PARAMS_UPDATE_POPUP_HEIGHT, AAFwk::Integer::Box(popupSize.height)); + isValueChanged = true; + } + int popupPlacement = 0; + if (AppExecFwk::GetFieldIntByName(env, autoFillPopupConfigObj, CONFIG_POPUP_PLACEMENT, popupPlacement)) { + wantParams.SetParam(WANT_PARAMS_UPDATE_POPUP_PLACEMENT, AAFwk::Integer::Box(popupPlacement)); + isValueChanged = true; + } + return isValueChanged; +} + +void EtsFillRequestCallback::SendResultCodeAndViewData(const EtsAutoFillExtensionUtil::AutoFillResultCode &resultCode, + const std::string &etsString) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (uiWindow_ == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow"); + return; + } + + AAFwk::Want want; + if (resultCode == EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_SUCESS) { + want.SetParam(WANT_PARAMS_VIEW_DATA, etsString); + want.SetParam(WANT_PARAMS_AUTO_FILL_CMD, WANT_PARAMS_AUTO_FILL_CMD_AUTOFILL); + } + + if (resultCode == EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_CANCEL) { + want.SetParam(WANT_PARAMS_FILL_CONTENT, etsString); + } + + auto ret = uiWindow_->TransferAbilityResult(resultCode, want); + if (ret != Rosen::WMError::WM_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "TransferAbilityResult failed"); + return; + } + + auto errorCode = AAFwk::AbilityManagerClient::GetInstance()->TerminateUIExtensionAbility(sessionInfo_); + if (errorCode != ERR_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "TerminateUIExtensionAbility error: %{public}d", errorCode); + } +} + +ani_object EtsFillRequestCallback::CreateEtsFillRequestCallback(ani_env *env, + const sptr &sessionInfo, const sptr &uiWindow) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return nullptr; + } + if (sessionInfo == nullptr || uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo or uiWindow"); + return nullptr; + } + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass(FILL_REQUEST_CALL_BACK_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find class status: %{public}d", status); + return nullptr; + } + std::array functions = { + ani_native_function { "onSuccess", "Lapplication/AutoFillRequest/FillResponse;:V", + reinterpret_cast(EtsFillRequestCallback::FillRequestSuccess) }, + ani_native_function { "onFailure", ":V", + reinterpret_cast(EtsFillRequestCallback::FillRequestFailed) }, + ani_native_function { "onCancel", "Lstd/core/String;:V", + reinterpret_cast(EtsFillRequestCallback::FillRequestCanceled) }, + ani_native_function { "setAutoFillPopupConfig", "Lapplication/AutoFillRequest/AutoFillPopupConfig;:V", + reinterpret_cast(EtsFillRequestCallback::FillRequestAutoFillPopupConfig) }, + }; + if ((status = env->Class_BindNativeMethods(cls, functions.data(), functions.size())) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "bind method status : %{public}d", status); + return nullptr; + } + ani_class cleanerCls = nullptr; + if ((status = env->FindClass(CLEANER_CLASS, &cleanerCls)) != ANI_OK || cleanerCls == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Cleaner FindClass failed status: %{public}d, or null cleanerCls", status); + return nullptr; + } + std::array cleanerMethods = { + ani_native_function {"clean", nullptr, reinterpret_cast(EtsFillRequestCallback::Clean) }, + }; + if ((status = env->Class_BindNativeMethods(cleanerCls, cleanerMethods.data(), cleanerMethods.size())) != + ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "cleanerCls Class_BindNativeMethods failed status: %{public}d", status); + return nullptr; + } + ani_object contextObj = SetEtsFillRequestCallback(env, sessionInfo, uiWindow); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null contextObj"); + return nullptr; + } + return contextObj; +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/auto_fill_extension_ability/src/ets_save_request_callback.cpp b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_save_request_callback.cpp new file mode 100644 index 00000000000..ddc4884d173 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_save_request_callback.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2025 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 "ets_save_request_callback.h" + +#include "ability_manager_client.h" +#include "ani_common_util.h" +#include "ets_error_utils.h" +#include "hilog_tag_wrapper.h" +#include "int_wrapper.h" +#include "ipc_skeleton.h" +#include "tokenid_kit.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *SAVE_REQUEST_CALL_BACK_CLASS_NAME = "Lapplication/AutoFillRequest/SaveRequestCallbackInner;"; +constexpr const char *CLEANER_CLASS = "Lapplication/AutoFillRequest/Cleaner;"; +} + +EtsSaveRequestCallback::EtsSaveRequestCallback( + const sptr &sessionInfo, const sptr &uiWindow) + : sessionInfo_(sessionInfo), uiWindow_(uiWindow) +{} + +ani_object EtsSaveRequestCallback::SetEtsSaveRequestCallback(ani_env *env, const sptr &sessionInfo, + const sptr &uiWindow) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "SetEtsSaveRequestCallback Call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return nullptr; + } + if (sessionInfo == nullptr || uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo or uiWindow"); + return nullptr; + } + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass(SAVE_REQUEST_CALL_BACK_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find class status: %{public}d", status); + return nullptr; + } + ani_method method = nullptr; + if ((status = env->Class_FindMethod(cls, "", "J:V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find method status: %{public}d", status); + return nullptr; + } + auto etsSaveRequestCallback = new (std::nothrow) EtsSaveRequestCallback(sessionInfo, uiWindow); + if (etsSaveRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "etsSaveRequestCallback nullptr"); + return nullptr; + } + ani_object contextObj = nullptr; + if ((status = env->Object_New(cls, method, &contextObj, reinterpret_cast(etsSaveRequestCallback))) + != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "new object status: %{public}d", status); + delete etsSaveRequestCallback; + etsSaveRequestCallback = nullptr; + return nullptr; + } + return contextObj; +} + +EtsSaveRequestCallback *EtsSaveRequestCallback::GetEtsSaveRequestCallback(ani_env *env, ani_object object) +{ + if (env == nullptr || object == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env or object"); + return nullptr; + } + ani_long saveRequestCallbackInnerPtr = 0; + ani_status status = env->Object_GetFieldByName_Long(object, "saveRequestCallbackInnerPtr", + &saveRequestCallbackInnerPtr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "saveRequestCallbackInnerPtr GetField status: %{public}d", status); + return nullptr; + } + auto etsSaveRequestCallback = reinterpret_cast(saveRequestCallbackInnerPtr); + if (etsSaveRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "etsSaveRequestCallback null"); + return nullptr; + } + return etsSaveRequestCallback; +} + +void EtsSaveRequestCallback::Clean(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Clean called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_long ptr = 0; + ani_status status = env->Object_GetFieldByName_Long(object, "ptr", &ptr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "ptr GetField status: %{public}d", status); + return; + } + if (ptr != 0) { + delete reinterpret_cast(ptr); + } +} + +void EtsSaveRequestCallback::SaveRequestSuccess(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "SaveRequestSuccess called"); + auto etsSaveRequestCallback = GetEtsSaveRequestCallback(env, object); + if (etsSaveRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsSaveRequestCallback"); + return; + } + etsSaveRequestCallback->OnSaveRequestSuccess(env, object); +} + +void EtsSaveRequestCallback::SaveRequestFailed(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "SaveRequestFailed called"); + auto etsSaveRequestCallback = GetEtsSaveRequestCallback(env, object); + if (etsSaveRequestCallback == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsSaveRequestCallback"); + return; + } + etsSaveRequestCallback->OnSaveRequestFailed(env, object); +} + +void EtsSaveRequestCallback::OnSaveRequestSuccess(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_SUCESS); +} + +void EtsSaveRequestCallback::OnSaveRequestFailed(ani_env *env, ani_object object) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED); +} + +void EtsSaveRequestCallback::SendResultCodeAndViewData(const EtsAutoFillExtensionUtil::AutoFillResultCode &resultCode) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (uiWindow_ == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow_"); + return; + } + + AAFwk::Want want; + auto ret = uiWindow_->TransferAbilityResult(resultCode, want); + if (ret != Rosen::WMError::WM_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "TransferAbilityResult failed"); + return; + } + + auto errorCode = AAFwk::AbilityManagerClient::GetInstance()->TerminateUIExtensionAbility(sessionInfo_); + if (errorCode != ERR_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "TerminateUIExtensionAbility error: %{public}d", errorCode); + } +} + +ani_object EtsSaveRequestCallback::CreateEtsSaveRequestCallback(ani_env *env, + const sptr &sessionInfo, const sptr &uiWindow) +{ + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return nullptr; + } + if (sessionInfo == nullptr || uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo or uiWindow"); + return nullptr; + } + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass(SAVE_REQUEST_CALL_BACK_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find class status: %{public}d", status); + return nullptr; + } + std::array functions = { + ani_native_function { "onSuccess", ":V", + reinterpret_cast(EtsSaveRequestCallback::SaveRequestSuccess) }, + ani_native_function { "onFailure", ":V", + reinterpret_cast(EtsSaveRequestCallback::SaveRequestFailed) }, + }; + if ((status = env->Class_BindNativeMethods(cls, functions.data(), functions.size())) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "bind method status : %{public}d", status); + return nullptr; + } + ani_class cleanerCls = nullptr; + if ((status = env->FindClass(CLEANER_CLASS, &cleanerCls)) != ANI_OK || cleanerCls == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Cleaner FindClass failed status: %{public}d, or null cleanerCls", status); + return nullptr; + } + std::array cleanerMethods = { + ani_native_function {"clean", nullptr, reinterpret_cast(EtsSaveRequestCallback::Clean) }, + }; + if ((status = env->Class_BindNativeMethods(cleanerCls, cleanerMethods.data(), cleanerMethods.size())) != + ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "cleanerCls Class_BindNativeMethods failed status: %{public}d", status); + return nullptr; + } + ani_object contextObj = SetEtsSaveRequestCallback(env, sessionInfo, uiWindow); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null contextObj"); + return nullptr; + } + return contextObj; +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index 128a246f4b8..a9f38391104 100644 --- a/frameworks/ets/ets/BUILD.gn +++ b/frameworks/ets/ets/BUILD.gn @@ -383,6 +383,38 @@ ohos_prebuilt_etc("ability_runtime_running_multi_appinfo_abc_etc") { deps = [ ":ability_runtime_running_multi_appinfo_abc" ] } +generate_static_abc("ability_runtime_page_node_info_abc") { + base_url = "./" + files = [ "./application/PageNodeInfo.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_page_node_info_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_page_node_info_abc_etc") { + source = "$target_out_dir/ability_runtime_page_node_info_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_page_node_info_abc" ] +} + +generate_static_abc("ability_runtime_view_data_abc") { + base_url = "./" + files = [ "./application/ViewData.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_view_data_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_view_data_abc_etc") { + source = "$target_out_dir/ability_runtime_view_data_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_view_data_abc" ] +} + generate_static_abc("ability_runtime_multi_app_mode_abc") { base_url = "./" files = [ "./application/MultiAppMode.ets" ] @@ -958,6 +990,70 @@ ohos_prebuilt_etc("ability_runtime_connect_options_abc_etc") { deps = [ ":ability_runtime_connect_options_abc" ] } +generate_static_abc("ability_runtime_auto_fill_extension_context_abc") { + base_url = "./" + files = [ "./application/AutoFillExtensionContext.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_auto_fill_extension_context_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_auto_fill_extension_context_abc_etc") { + source = "$target_out_dir/ability_runtime_auto_fill_extension_context_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_auto_fill_extension_context_abc" ] +} + +generate_static_abc("ability_runtime_auto_fill_popup_config_abc") { + base_url = "./" + files = [ "./application/AutoFillPopupConfig.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_auto_fill_popup_config_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_auto_fill_popup_config_abc_etc") { + source = "$target_out_dir/ability_runtime_auto_fill_popup_config_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_auto_fill_popup_config_abc" ] +} + +generate_static_abc("ability_runtime_auto_fill_rect_abc") { + base_url = "./" + files = [ "./application/AutoFillRect.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_auto_fill_rect_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_auto_fill_rect_abc_etc") { + source = "$target_out_dir/ability_runtime_auto_fill_rect_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_auto_fill_rect_abc" ] +} + +generate_static_abc("ability_runtime_auto_fill_request_abc") { + base_url = "./" + files = [ "./application/AutoFillRequest.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_auto_fill_request_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_auto_fill_request_abc_etc") { + source = "$target_out_dir/ability_runtime_auto_fill_request_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_auto_fill_request_abc" ] +} + generate_static_abc("ability_runtime_auto_fill_type_abc") { base_url = "./" files = [ "./application/AutoFillType.ets" ] @@ -1290,7 +1386,11 @@ group("ets_packages") { ":ability_runtime_app_manager_abc_etc", ":ability_runtime_app_state_data_abc_etc", ":ability_runtime_application_context_abc_etc", + ":ability_runtime_auto_fill_extension_context_abc_etc", ":ability_runtime_auto_fill_manager_abc_etc", + ":ability_runtime_auto_fill_popup_config_abc_etc", + ":ability_runtime_auto_fill_rect_abc_etc", + ":ability_runtime_auto_fill_request_abc_etc", ":ability_runtime_auto_fill_type_abc_etc", ":ability_runtime_application_state_change_callback_abc_etc", ":ability_runtime_base_context_abc_etc", @@ -1323,10 +1423,12 @@ group("ets_packages") { ":ability_runtime_ui_ability_abc_etc", ":ability_runtime_ui_ability_context_abc_etc", ":ability_runtime_multi_app_mode_abc_etc", + ":ability_runtime_page_node_info_abc_etc", ":ability_runtime_process_data_abc_etc", ":ability_runtime_process_information_abc_etc", ":ability_runtime_running_app_clone_abc_etc", ":ability_runtime_running_multi_appinfo_abc_etc", + ":ability_runtime_view_data_abc_etc", ":ability_runtime_want_abc_etc", ":ability_runtime_want_agent_abc_etc", ":ability_runtime_want_agent_info_abc_etc", diff --git a/frameworks/ets/ets/application/AutoFillExtensionContext.ets b/frameworks/ets/ets/application/AutoFillExtensionContext.ets new file mode 100644 index 00000000000..c6ce791fe49 --- /dev/null +++ b/frameworks/ets/ets/application/AutoFillExtensionContext.ets @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 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 ExtensionContext from 'application.ExtensionContext'; +import type CustomData from './CustomData'; +import AsyncCallbackWrapper from '../utils/AbilityUtils'; +import { BusinessError } from '@ohos.base'; + +class Cleaner { + public ptr: long = 0; + + constructor(ptr: long) { + this.ptr = ptr; + } + + native clean(): void; +} +export function callback(cleaner: Cleaner): void { + cleaner.clean(); +} +let destroyRegister = new FinalizationRegistry(callback); +let unregisterToken = new object(); + +export default class AutoFillExtensionContext extends ExtensionContext { + autoFillExtensionContextPtr: long = 0; + private cleaner: Cleaner | null = null; + constructor(ptr: long) { + if(this.autoFillExtensionContextPtr == 0){ + this.autoFillExtensionContextPtr = ptr; + } + this.registerCleaner(this.autoFillExtensionContextPtr) + } + registerCleaner(ptr: long): void { + this.cleaner = new Cleaner(ptr) + destroyRegister.register(this, this.cleaner!, unregisterToken); + } + unregisterCleaner(): void { + destroyRegister.unregister(unregisterToken); + } + + public native nativeReloadInModal(customData: CustomData, callback: AsyncCallbackWrapper): void; + reloadInModal(customData: CustomData): Promise { + let p = + new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let asyncCall = new AsyncCallbackWrapper((err: BusinessError | null) => { + if (err == null || err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeReloadInModal(customData, asyncCall); + }).catch((err: Error): void => { + reject(err as BusinessError); + }); + }); + return p; + } +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/AutoFillPopupConfig.ets b/frameworks/ets/ets/application/AutoFillPopupConfig.ets new file mode 100644 index 00000000000..980aa45b94b --- /dev/null +++ b/frameworks/ets/ets/application/AutoFillPopupConfig.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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 AutoFillPopupConfig { + popupSize?: PopupSize; + placement?: PopupPlacement; +} +export interface PopupSize { + width: double; + height: double; +} +export enum PopupPlacement { + LEFT = 0, + RIGHT = 1, + TOP = 2, + BOTTOM = 3, + TOP_LEFT = 4, + TOP_RIGHT = 5, + BOTTOM_LEFT = 6, + BOTTOM_RIGHT = 7, + LEFT_TOP = 8, + LEFT_BOTTOM = 9, + RIGHT_TOP = 10, + RIGHT_BOTTOM = 11, + NONE = 12 +} + +class AutoFillPopupConfigImpl implements AutoFillPopupConfig { + public popupSize?: PopupSize; + public placement?: PopupPlacement; +} +class PopupSizeImpl implements PopupSize { + public width: double; + public height: double; +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/AutoFillRect.ets b/frameworks/ets/ets/application/AutoFillRect.ets new file mode 100644 index 00000000000..2f8a653358a --- /dev/null +++ b/frameworks/ets/ets/application/AutoFillRect.ets @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 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 AutoFillRect { + left: double; + top: double; + width: double; + height: double; +} + +class AutoFillRectImpl implements AutoFillRect { + public left: double; + public top: double; + public width: double; + public height: double; +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/AutoFillRequest.ets b/frameworks/ets/ets/application/AutoFillRequest.ets new file mode 100644 index 00000000000..ad7441c5e7f --- /dev/null +++ b/frameworks/ets/ets/application/AutoFillRequest.ets @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025 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 { AutoFillType } from 'application.AutoFillType'; +import type CustomData from './CustomData'; +import type AutoFillPopupConfig from './AutoFillPopupConfig'; +import type ViewData from './ViewData'; + +export interface FillRequest { + type: AutoFillType; + viewData: ViewData; + customData: CustomData; + isPopup: boolean; +} +export interface SaveRequest { + viewData: ViewData; +} +export interface UpdateRequest { + viewData: ViewData; +} +export interface FillResponse { + viewData: ViewData; +} +export interface FillRequestCallback { + onSuccess(response: FillResponse): void; + onFailure(): void; + onCancel(fillContent?: string): void; + setAutoFillPopupConfig(autoFillPopupConfig: AutoFillPopupConfig): void; +} +export interface SaveRequestCallback { + onSuccess(): void; + onFailure(): void; +} + +class FillRequestInner implements FillRequest { + public type: AutoFillType = AutoFillType.UNSPECIFIED; + public viewData: ViewData = {}; + public customData: CustomData = {}; + public isPopup: boolean; +} +class SaveRequestInner implements SaveRequest { + public viewData: ViewData = {}; +} +class UpdateRequestInner implements UpdateRequest { + public viewData: ViewData = {}; +} +class FillResponseInner implements FillResponse { + public viewData: ViewData = {}; +} + +class Cleaner { + public ptr: long = 0; + + constructor(ptr: long) { + this.ptr = ptr; + } + + native clean(): void; +} +export function callback(cleaner: Cleaner): void { + cleaner.clean(); +} +let destroyRegister = new FinalizationRegistry(callback); +let unregisterToken = new object(); + +class FillRequestCallbackInner implements FillRequestCallback { + fillRequestCallbackInnerPtr: long = 0; + private cleaner: Cleaner | null = null; + constructor(ptr: long) { + if(this.fillRequestCallbackInnerPtr == 0){ + this.fillRequestCallbackInnerPtr = ptr; + } + this.registerCleaner(this.fillRequestCallbackInnerPtr) + } + registerCleaner(ptr: long): void { + this.cleaner = new Cleaner(ptr) + destroyRegister.register(this, this.cleaner!, unregisterToken); + } + unregisterCleaner(): void { + destroyRegister.unregister(unregisterToken); + } + + public native onSuccess(response: FillResponse): void; + public native onFailure(): void; + public native onCancel(fillContent?: string): void; + public native setAutoFillPopupConfig(autoFillPopupConfig: AutoFillPopupConfig): void; +} + +class SaveRequestCallbackInner implements SaveRequestCallback { + saveRequestCallbackInnerPtr: long = 0; + private cleaner: Cleaner | null = null; + constructor(ptr: long) { + if(this.saveRequestCallbackInnerPtr == 0){ + this.saveRequestCallbackInnerPtr = ptr; + } + this.registerCleaner(this.saveRequestCallbackInnerPtr) + } + registerCleaner(ptr: long): void { + this.cleaner = new Cleaner(ptr) + destroyRegister.register(this, this.cleaner!, unregisterToken); + } + unregisterCleaner(): void { + destroyRegister.unregister(unregisterToken); + } + + public native onSuccess(): void; + public native onFailure(): void; +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/PageNodeInfo.ets b/frameworks/ets/ets/application/PageNodeInfo.ets new file mode 100644 index 00000000000..40155faf3e4 --- /dev/null +++ b/frameworks/ets/ets/application/PageNodeInfo.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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 { AutoFillType } from 'application.AutoFillType'; +import type AutoFillRect from './AutoFillRect'; + +export default interface PageNodeInfo { + id: int; + depth: int; + autoFillType: AutoFillType; + tag: string; + value: string; + placeholder?: string; + passwordRules?: string; + enableAutoFill: boolean; + rect: AutoFillRect; + isFocus: boolean; + metadata?: string; +} + +class PageNodeInfoImpl implements PageNodeInfo { + public id: int; + public depth: int; + public autoFillType: AutoFillType = AutoFillType.UNSPECIFIED; + public tag: string = ''; + public value: string = ''; + public placeholder?: string = ''; + public passwordRules?: string = ''; + public enableAutoFill: boolean; + public rect: AutoFillRect = {}; + public isFocus: boolean; + public metadata?: string = ''; +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/ViewData.ets b/frameworks/ets/ets/application/ViewData.ets new file mode 100644 index 00000000000..41c9e320908 --- /dev/null +++ b/frameworks/ets/ets/application/ViewData.ets @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 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 PageNodeInfo from './PageNodeInfo'; +import AutoFillRect from './AutoFillRect'; + +export default interface ViewData { + bundleName: string; + moduleName: string; + abilityName: string; + pageUrl: string; + pageNodeInfos: Array; + pageRect: AutoFillRect; + isUserSelected: boolean; + isOtherAccount: boolean; +} + +class ViewDataImpl implements ViewData { + public bundleName: string = ''; + public moduleName: string = ''; + public abilityName: string = ''; + public pageUrl: string = ''; + public pageNodeInfos: Array = []; + public pageRect: AutoFillRect = {}; + public isUserSelected: boolean; + public isOtherAccount: boolean; +} \ No newline at end of file diff --git a/frameworks/native/ability/native/BUILD.gn b/frameworks/native/ability/native/BUILD.gn index c08f25d7acb..60ab9f61d64 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -2876,6 +2876,58 @@ ohos_shared_library("auto_fill_extension") { part_name = "ability_runtime" } +ohos_shared_library("auto_fill_extension_ani") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + + include_dirs = [ + "${ability_runtime_path}/frameworks/ets/ani/auto_fill_extension_ability/include", + ] + + public_configs = [ ":auto_fill_extension_config" ] + + sources = [] + + deps = [ + ":abilitykit_native", + ":auto_fill_extension", + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_native_path}/ability/native:ability_business_error", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + ] + + external_deps = [ + "ability_base:session_info", + "ability_base:view_data", + "ability_base:want", + "access_token:libtokenid_sdk", + "hilog:libhilog", + "runtime_core:ani", + ] + + if (ability_runtime_auto_fill) { + sources += [ + "${ability_runtime_path}/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_context.cpp", + "${ability_runtime_path}/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_util.cpp", + "${ability_runtime_path}/frameworks/ets/ani/auto_fill_extension_ability/src/ets_fill_request_callback.cpp", + "${ability_runtime_path}/frameworks/ets/ani/auto_fill_extension_ability/src/ets_save_request_callback.cpp", + ] + } + + if (ability_runtime_graphics) { + external_deps += [ "window_manager:libwm" ] + } + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} + ohos_shared_library("auto_fill_extension_util") { sanitize = { integer_overflow = true -- Gitee