diff --git a/bundle.json b/bundle.json index 7b67a689da95cd010bd587aaeb6aa8be8341f664..31f72b0f2d6fa65aae8611f593278d35192b420a 100644 --- a/bundle.json +++ b/bundle.json @@ -126,6 +126,7 @@ "//foundation/ability/ability_runtime/tools:tools_target", "//foundation/ability/ability_runtime/interfaces/inner_api:innerkits_target", "//foundation/ability/ability_runtime/frameworks/native/ability/native:ability_thread", + "//foundation/ability/ability_runtime/frameworks/native/ability/native:auto_fill_extension_ani", "//foundation/ability/ability_runtime/frameworks/native/ability/native:extension_module", "//foundation/ability/ability_runtime/frameworks/native/ability/native:insight_intent_executor_ani", "//foundation/ability/ability_runtime/frameworks/native/ability/native:service_extension_ani", diff --git a/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension.h b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..d25519d34e8c5e58689737bcb83a3a7d35191b26 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension.h @@ -0,0 +1,152 @@ +/* + * 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_H +#define OHOS_ABILITY_RUNTIME_ETS_AUTO_FILL_EXTENSION_H + +#include "auto_fill_extension.h" +#include "auto_fill_extension_context.h" +#include "configuration.h" +#include "ets_runtime.h" +#include "session_info.h" +#include "view_data.h" + +namespace OHOS { +namespace AbilityRuntime { +/** + * @brief Basic ets auto fill extension (EtsAutoFillExtension). + */ +class EtsAutoFillExtension : public AutoFillExtension, public IAutoFillExtensionCallback { +public: + explicit EtsAutoFillExtension(ETSRuntime &etsRuntime); + virtual ~EtsAutoFillExtension() override; + + static EtsAutoFillExtension *Create(const std::unique_ptr &runtime); + + /** + * @brief Init the auto fill extension. + * + * @param record the auto fill extension record. + * @param application the application info. + * @param handler the auto fill extension handler. + * @param token the remote token. + */ + void Init(const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, const sptr &token) override; + + /** + * @brief Called when this ui extension is started. You must override this function if you want to perform some + * initialization operations during ui extension startup. + * + * This function can be called only once in the entire lifecycle of an ui extension. + * + * @param Want Indicates the {@link Want} structure containing startup information about the ui extension. + * @param sessionInfo The session info of the ability. + */ + void OnStart(const AAFwk::Want &want, sptr sessionInfo) override; + + /** + * @brief Called back when ui extension is started. + * + * This method can be called only by ui extension. You can use the StartAbility(Want) method to start + * ui extension. Then the system calls back the current method to use the transferred want parameter to + * execute its own logic. + * + * @param want Indicates the want of ui extension to start. + * @param restart Indicates the startup mode. The value true indicates that ui extension is restarted after being + * destroyed, and the value false indicates a normal startup. + * @param startId Indicates the number of times the ui extension has been started. The startId is incremented + * by 1 every time the ui extension is started. For example, if the ui extension has been started for six times, the + * value of startId is 6. + */ + void OnCommand(const AAFwk::Want &want, bool restart, int startId) override; + + void OnCommandWindow( + const AAFwk::Want &want, const sptr &sessionInfo, AAFwk::WindowCommand winCmd) override; + + /** + * @brief Called when this ui extension enters the STATE_STOP state. + * + * The ui extension in the STATE_STOP is being destroyed. + * You can override this function to implement your own processing logic. + */ + void OnStop() override; + void OnStop(AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback) override; + /** + * @brief The callback of OnStop. + */ + void OnStopCallBack() override; + + /** + * @brief Called when this extension enters the STATE_FOREGROUND state. + * + * + * The extension in the STATE_FOREGROUND state is visible. + * You can override this function to implement your own processing logic. + */ + void OnForeground(const Want &want, sptr sessionInfo) override; + + /** + * @brief Called when this extension enters the STATE_BACKGROUND state. + * + * + * The extension in the STATE_BACKGROUND state is invisible. + * You can override this function to implement your own processing logic. + */ + void OnBackground() override; + + /** + * @brief Used to create an update request. + * + * @param wantParams Indicates the view data of the update request. + */ + void UpdateRequest(const AAFwk::WantParams &wantParams); + + int32_t OnReloadInModal(const sptr &sessionInfo, const CustomData &customData) override; + + static void OnDestroyCallback(ani_env *env, ani_object aniObj); + +private: + virtual void BindContext(); + bool CallObjectMethod(bool withResult, const char *name, const char *signature, ...); + void ForegroundWindow(const AAFwk::Want &want, sptr sessionInfo); + void BackgroundWindow(sptr sessionInfo); + void DestroyWindow(sptr sessionInfo); + + void OnCommandWindowDone(const sptr &sessionInfo, AAFwk::WindowCommand winCmd) override; + bool HandleAutoFillCreate(const AAFwk::Want &want, sptr sessionInfo); + void CallEtsOnRequest(const AAFwk::Want &want, sptr sessionInfo, sptr uiWindow); + void RegisterTransferComponentDataListener(sptr uiWindow); + bool BindNativeMethods(); + void ReleaseObjectReference(ani_ref etsObjRef); + bool CreateNewWindow(sptr sessionInfo, sptr obj, + std::shared_ptr sharedWant); + bool CreateSessionAndReference(sptr sessionInfo, sptr uiWindow); + void ProcessRequest(const AAFwk::Want &want, sptr sessionInfo, sptr uiWindow, + ani_object nativeContentSession); + + ETSRuntime &etsRuntime_; + std::shared_ptr etsObj_; + std::shared_ptr shellContextRef_ = nullptr; + std::map, sptr> uiWindowMap_; + std::set> foregroundWindows_; + std::map, ani_ref> contentSessions_; + std::map, ani_ref> callbacks_; + bool isPopup_ = false; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_AUTO_FILL_EXTENSION_H \ No newline at end of file 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 0000000000000000000000000000000000000000..8cedef6e4a21c06b43e3ab0876fe628aacf16d6f --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_context.h @@ -0,0 +1,42 @@ +/* + * 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(std::shared_ptr context) + : context_(context) {} + virtual ~EtsAutoFillExtensionContext() = default; + + static ani_object SetEtsAutoFillExtensionContext(ani_env *env, 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, + 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_instance.h b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_instance.h new file mode 100644 index 0000000000000000000000000000000000000000..53e5cb5a7a12cb6f5a9241100b85a4a73737db93 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_instance.h @@ -0,0 +1,29 @@ +/* + * 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_INSTANCE_H +#define OHOS_ABILITY_RUNTIME_ETS_AUTO_FILL_EXTENSION_INSTANCE_H + +#include "auto_fill_extension.h" + +namespace OHOS { +namespace AbilityRuntime { +class AutoFillExtension; +class Runtime; + +AutoFillExtension *CreateETSAutoFillExtension(const std::unique_ptr &runtime); +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_AUTO_FILL_EXTENSION_INSTANCE_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 0000000000000000000000000000000000000000..4400afd84b3a30c1679622f53d1157859878b5b6 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/include/ets_auto_fill_extension_util.h @@ -0,0 +1,83 @@ +/* + * 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 ani_object WrapFillRequest(ani_env *env, const AAFwk::Want &want); + static ani_object WrapUpdateRequest(ani_env *env, const AAFwk::WantParams &wantParams); + static ani_object WrapViewData(ani_env *env, const AbilityBase::ViewData &viewData); + static ani_object WrapPageNodeInfo(ani_env *env, const AbilityBase::PageNodeInfo &pageNodeInfo); + static ani_object WrapRectData(ani_env *env, const AbilityBase::Rect &rect); + static ani_object WrapCustomData(ani_env *env, const AAFwk::WantParams ¶m); + 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 bool CreateObject(ani_env *env, ani_object &object, const std::string &className); + static ani_object SetFillRequest(ani_env *env, ani_object object, const AAFwk::Want &want); + static ani_object SetViewData(ani_env *env, ani_object object, const AbilityBase::ViewData &viewData); + static void SetViewDataArray(ani_env *env, ani_object &object, const AbilityBase::ViewData &viewData); + static ani_object SetPageNodeInfo(ani_env *env, ani_object object, const AbilityBase::PageNodeInfo &pageNodeInfo); + static ani_object SetRectData(ani_env *env, ani_object object, const AbilityBase::Rect &rect); + 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 0000000000000000000000000000000000000000..6c6b441e63267e5630e98437bb4a15ca2748dced --- /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(sptr sessionInfo, sptr uiWindow); + virtual ~EtsFillRequestCallback() = default; + + static ani_object SetEtsFillRequestCallback(ani_env *env, sptr sessionInfo, + 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, sptr sessionInfo, + 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 0000000000000000000000000000000000000000..4e81ff9313b7686e8bae3f9a7f6be7a1d3e04c0b --- /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(sptr sessionInfo, sptr uiWindow); + virtual ~EtsSaveRequestCallback() = default; + + static ani_object SetEtsSaveRequestCallback(ani_env *env, sptr sessionInfo, + 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, sptr sessionInfo, + 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.cpp b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce624de93226c148bd8847a9e60b10491209ab03 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension.cpp @@ -0,0 +1,748 @@ +/* + * 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.h" + +#include "ability_manager_client.h" +#include "ani_common_want.h" +#include "ani_extension_window.h" +#include "connection_manager.h" +#include "ets_auto_fill_extension_context.h" +#include "ets_auto_fill_extension_util.h" +#include "ets_extension_common.h" +#include "ets_fill_request_callback.h" +#include "ets_native_reference.h" +#include "ets_save_request_callback.h" +#include "ets_ui_extension_content_session.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" +#include "int_wrapper.h" +#include "want_params_wrapper.h" + +#ifdef WINDOWS_PLATFORM +#define ETS_EXPORT __declspec(dllexport) +#else +#define ETS_EXPORT __attribute__((visibility("default"))) +#endif + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *WANT_PARAMS_AUTO_FILL_CMD = "ohos.ability.params.autoFillCmd"; +constexpr static char WANT_PARAMS_AUTO_FILL_EVENT_KEY[] = "ability.want.params.AutoFillEvent"; +constexpr const char *WANT_PARAMS_CUSTOM_DATA = "ohos.ability.params.customData"; +constexpr const char *WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY = "ohos.ability.params.popupWindow"; +constexpr const char *AUTO_FILL_EXTENSION_CLASS_NAME = + "L@ohos/app/ability/AutoFillExtensionAbility/AutoFillExtensionAbility;"; +constexpr const char *ON_REQUEST_METHOD_NAME = "L@ohos/app/ability/Want/Want;I:V"; +constexpr const char *ON_SESSION_DESTROY_METHOD_NAME = + "L@ohos/app/ability/UIExtensionContentSession/UIExtensionContentSession;:V"; +constexpr const char *ON_SAVE_REQUEST_METHOD_NAME = + "L@ohos/app/ability/UIExtensionContentSession/UIExtensionContentSession;" + "Lapplication/AutoFillRequest/SaveRequest;Lapplication/AutoFillRequest/SaveRequestCallback;:V"; +constexpr const char *ON_FILL_REQUEST_METHOD_NAME = + "L@ohos/app/ability/UIExtensionContentSession/UIExtensionContentSession;" + "Lapplication/AutoFillRequest/FillRequest;Lapplication/AutoFillRequest/FillRequestCallback;:V"; +} + +EtsAutoFillExtension *EtsAutoFillExtension::Create(const std::unique_ptr &runtime) +{ + return new (std::nothrow) EtsAutoFillExtension(static_cast(*runtime)); +} + +EtsAutoFillExtension::EtsAutoFillExtension(ETSRuntime &etsRuntime) : etsRuntime_(etsRuntime) +{ +} + +EtsAutoFillExtension::~EtsAutoFillExtension() +{ + auto context = GetContext(); + if (context) { + context->Unbind(); + } + if (shellContextRef_) { + ReleaseObjectReference(shellContextRef_->aniRef); + } + for (auto &item : contentSessions_) { + ReleaseObjectReference(item.second); + } + contentSessions_.clear(); + for (auto &callback : callbacks_) { + ReleaseObjectReference(callback.second); + } + callbacks_.clear(); +} + +void EtsAutoFillExtension::Init(const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, const sptr &token) +{ + AutoFillExtension::Init(record, application, handler, token); + if (abilityInfo_ == nullptr || abilityInfo_->srcEntrance.empty()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null abilityInfo"); + return; + } + std::string srcPath(abilityInfo_->moduleName + "/"); + srcPath.append(abilityInfo_->srcEntrance); + auto pos = srcPath.rfind("."); + if (pos != std::string::npos) { + srcPath.erase(pos); + srcPath.append(".abc"); + } + std::string moduleName(abilityInfo_->moduleName); + moduleName.append("::").append(abilityInfo_->name); + etsObj_ = etsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath, + abilityInfo_->compileMode == AppExecFwk::CompileMode::ES_MODULE, false, abilityInfo_->srcEntrance); + if (etsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "etsObj_ null"); + return; + } + if (!BindNativeMethods()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "BindNativeMethods failed"); + return; + } + BindContext(); + SetExtensionCommon( + EtsExtensionCommon::Create(etsRuntime_, static_cast(*etsObj_), shellContextRef_)); +} + +bool EtsAutoFillExtension::BindNativeMethods() +{ + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return false; + } + std::array functions = { + ani_native_function { "nativeOnDestroyCallback", ":V", + reinterpret_cast(EtsAutoFillExtension::OnDestroyCallback) }, + }; + ani_class cls = nullptr; + ani_status status = env->FindClass(AUTO_FILL_EXTENSION_CLASS_NAME, &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "FindClass failed status: %{public}d", status); + return false; + } + if ((status = env->Class_BindNativeMethods(cls, functions.data(), functions.size())) != ANI_OK + && status != ANI_ALREADY_BINDED) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Class_BindNativeMethods status: %{public}d", status); + return false; + } + return true; +} + +void EtsAutoFillExtension::ReleaseObjectReference(ani_ref etsObjRef) +{ + if (etsObjRef == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsObjRef"); + return; + } + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_status status = ANI_ERROR; + if ((status = env->GlobalReference_Delete(etsObjRef)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "GlobalReference_Delete failed, status: %{public}d", status); + } +} + +void EtsAutoFillExtension::BindContext() +{ + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + auto context = GetContext(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null context"); + return; + } + context->SetAutoFillExtensionCallback(std::static_pointer_cast(shared_from_this())); + ani_object contextObj = EtsAutoFillExtensionContext::CreateEtsAutoFillExtensionContext(env, context); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null contextObj"); + return; + } + ani_field contextField; + auto status = env->Class_FindField(etsObj_->aniCls, "context", &contextField); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Class_FindField failed, status: %{public}d", status); + return; + } + ani_ref contextRef = nullptr; + if ((status = env->GlobalReference_Create(contextObj, &contextRef)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "GlobalReference_Create failed, status: %{public}d", status); + return; + } + if ((status = env->Object_SetField_Ref(etsObj_->aniObj, contextField, contextRef)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_SetField_Ref failed, status: %{public}d", status); + return; + } + shellContextRef_ = std::make_shared(); + shellContextRef_->aniObj = contextObj; + shellContextRef_->aniRef = contextRef; +} + +void EtsAutoFillExtension::OnStart(const AAFwk::Want &want, sptr sessionInfo) +{ + Extension::OnStart(want); + CallObjectMethod(false, "onCreate", ":V"); +} + +void EtsAutoFillExtension::OnStop() +{ + AutoFillExtension::OnStop(); + CallObjectMethod(false, "onDestroy", ":V"); + OnStopCallBack(); +} + +void EtsAutoFillExtension::OnStop(AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback) +{ + if (callbackInfo == nullptr) { + isAsyncCallback = false; + OnStop(); + return; + } + AutoFillExtension::OnStop(); + std::weak_ptr weakPtr = shared_from_this(); + auto asyncCallback = [extensionWeakPtr = weakPtr]() { + auto etsAutoFillExtension = extensionWeakPtr.lock(); + if (etsAutoFillExtension == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null Extension"); + return; + } + etsAutoFillExtension->OnStopCallBack(); + }; + callbackInfo->Push(asyncCallback); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr || etsObj_ == nullptr) { + isAsyncCallback = false; + OnStop(); + return; + }; + ani_long destroyCallbackPoint = reinterpret_cast(callbackInfo); + ani_status status = env->Object_SetFieldByName_Long(etsObj_->aniObj, "destroyCallbackPoint", destroyCallbackPoint); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_SetFieldByName_Long failed, status: %{public}d", status); + return; + } + isAsyncCallback = CallObjectMethod(true, "callOnDestroy", ":Z"); + if (!isAsyncCallback) { + OnStopCallBack(); + } +} + +void EtsAutoFillExtension::OnStopCallBack() +{ + auto context = GetContext(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null context"); + return; + } + + bool ret = ConnectionManager::GetInstance().DisconnectCaller(context->GetToken()); + if (ret) { + ConnectionManager::GetInstance().ReportConnectionLeakEvent(getpid(), gettid()); + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "service connection not disconnected"); + } + + auto applicationContext = Context::GetApplicationContext(); + if (applicationContext != nullptr) { + applicationContext->DispatchOnAbilityDestroy(etsObj_); + } +} + +void EtsAutoFillExtension::OnCommandWindow( + const AAFwk::Want &want, const sptr &sessionInfo, AAFwk::WindowCommand winCmd) +{ + if (sessionInfo == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo"); + return; + } + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Begin. persistentId: %{private}d, winCmd: %{public}d", + sessionInfo->persistentId, winCmd); + Extension::OnCommandWindow(want, sessionInfo, winCmd); + switch (winCmd) { + case AAFwk::WIN_CMD_FOREGROUND: + ForegroundWindow(want, sessionInfo); + break; + case AAFwk::WIN_CMD_BACKGROUND: + BackgroundWindow(sessionInfo); + break; + case AAFwk::WIN_CMD_DESTROY: + DestroyWindow(sessionInfo); + break; + default: + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Unsupported cmd"); + break; + } + OnCommandWindowDone(sessionInfo, winCmd); +} + +void EtsAutoFillExtension::OnCommandWindowDone(const sptr &sessionInfo, + AAFwk::WindowCommand winCmd) +{ + auto context = GetContext(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null context"); + return; + } + AAFwk::AbilityCommand abilityCmd; + if (uiWindowMap_.empty()) { + abilityCmd = AAFwk::ABILITY_CMD_DESTROY; + } else if (foregroundWindows_.empty()) { + abilityCmd = AAFwk::ABILITY_CMD_BACKGROUND; + } else { + abilityCmd = AAFwk::ABILITY_CMD_FOREGROUND; + } + AAFwk::AbilityManagerClient::GetInstance()->ScheduleCommandAbilityWindowDone( + context->GetToken(), sessionInfo, winCmd, abilityCmd); +} + +void EtsAutoFillExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId) +{ + Extension::OnCommand(want, restart, startId); + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "begin restart= %{public}s, startId= %{public}d.", + restart ? "true" : "false", startId); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_ref wantRef = OHOS::AppExecFwk::WrapWant(env, want); + if (wantRef == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null wantRef"); + return; + } + CallObjectMethod(false, "onRequest", ON_REQUEST_METHOD_NAME, wantRef, static_cast(startId)); +} + +void EtsAutoFillExtension::OnForeground(const Want &want, sptr sessionInfo) +{ + Extension::OnForeground(want, sessionInfo); + ForegroundWindow(want, sessionInfo); + CallObjectMethod(false, "onForeground", ":V"); +} + +void EtsAutoFillExtension::OnBackground() +{ + CallObjectMethod(false, "onBackground", ":V"); + Extension::OnBackground(); +} + +void EtsAutoFillExtension::UpdateRequest(const AAFwk::WantParams &wantParams) +{ + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_object request = EtsAutoFillExtensionUtil::WrapUpdateRequest(env, wantParams); + if (request == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null request"); + return; + } + CallObjectMethod(false, "onUpdateRequest", ":V", request); +} + +int32_t EtsAutoFillExtension::OnReloadInModal(const sptr &sessionInfo, + const CustomData &customData) +{ + if (!isPopup_) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "current window type not popup"); + return ERR_INVALID_OPERATION; + } + + if (sessionInfo == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo"); + return ERR_NULL_OBJECT; + } + + AAFwk::WantParamWrapper wrapper(customData.data); + auto customDataString = wrapper.ToString(); + auto obj = sessionInfo->sessionToken; + auto &uiWindow = uiWindowMap_[obj]; + if (uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow"); + return ERR_NULL_OBJECT; + } + AAFwk::WantParams wantParams; + wantParams.SetParam(WANT_PARAMS_AUTO_FILL_CMD, + AAFwk::Integer::Box(static_cast(AutoFillCommand::RELOAD_IN_MODAL))); + wantParams.SetParam(WANT_PARAMS_CUSTOM_DATA, AAFwk::String::Box(customDataString)); + auto ret = static_cast(uiWindow->TransferExtensionData(wantParams)); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Transfer extension data failed"); + return ERR_INVALID_OPERATION; + } + return ERR_OK; +} + +void EtsAutoFillExtension::OnDestroyCallback(ani_env *env, ani_object aniObj) +{ + if (env == nullptr || aniObj == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env or null aniObj"); + return; + } + ani_long destroyCallbackPoint = 0; + ani_status status = ANI_ERROR; + if ((status = env->Object_GetFieldByName_Long(aniObj, "destroyCallbackPoint", &destroyCallbackPoint)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_GetFieldByName_Long failed, status: %{public}d", status); + return; + } + auto *callbackInfo = reinterpret_cast *>(destroyCallbackPoint); + if (callbackInfo == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null callbackInfo"); + return; + } + callbackInfo->Call(); + AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo); + if ((status = env->Object_SetFieldByName_Long(aniObj, "destroyCallbackPoint", + static_cast(0))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + } +} + +bool EtsAutoFillExtension::CreateSessionAndReference(sptr sessionInfo, + sptr uiWindow) +{ + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return false; + } + auto context = GetContext(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null context"); + return false; + } + std::weak_ptr weakContext = context; + std::shared_ptr abilityResultListeners = nullptr; + std::shared_ptr etsUiExtContentSession = + std::make_shared(sessionInfo, uiWindow, weakContext, abilityResultListeners); + ani_object nativeContentSession = EtsUIExtensionContentSession::CreateEtsUIExtensionContentSession( + env, sessionInfo, uiWindow, weakContext, abilityResultListeners, etsUiExtContentSession); + if (nativeContentSession == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null session"); + return false; + } + ani_status status = ANI_OK; + ani_ref ref = nullptr; + if ((status = env->GlobalReference_Create(nativeContentSession, &ref)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return false; + } + contentSessions_.emplace(sessionInfo->sessionToken, ref); + return true; +} + +bool EtsAutoFillExtension::CreateNewWindow(sptr sessionInfo, sptr obj, + std::shared_ptr sharedWant) +{ + sptr option = new Rosen::WindowOption(); + auto context = GetContext(); + if (context == nullptr || context->GetAbilityInfo() == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null context"); + return false; + } + option->SetWindowName(context->GetBundleName() + context->GetAbilityInfo()->name); + option->SetWindowType(Rosen::WindowType::WINDOW_TYPE_UI_EXTENSION); + option->SetWindowSessionType(Rosen::WindowSessionType::EXTENSION_SESSION); + option->SetParentId(sessionInfo->hostWindowId); + option->SetRealParentId(sessionInfo->realHostWindowId); + option->SetParentWindowType(static_cast(sessionInfo->parentWindowType)); + option->SetUIExtensionUsage(static_cast(sessionInfo->uiExtensionUsage)); + option->SetDensity(sessionInfo->density); + option->SetIsDensityFollowHost(sessionInfo->isDensityFollowHost); + option->SetDisplayId(sessionInfo->displayId); + if (context->isNotAllow != -1) { + bool isNotAllow = context->isNotAllow == 1 ? true : false; + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "isNotAllow: %{public}d", isNotAllow); + option->SetConstrainedModal(isNotAllow); + } + sptr uiWindow; + { + HITRACE_METER_NAME(HITRACE_TAG_APP, "Rosen::Window::Create"); + uiWindow = Rosen::Window::Create(option, GetContext(), sessionInfo->sessionToken); + } + if (uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow"); + return false; + } + uiWindow->UpdateExtensionConfig(sharedWant); + if (!CreateSessionAndReference(sessionInfo, uiWindow)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "create session failed"); + return false; + } + CallEtsOnRequest(*sharedWant, sessionInfo, uiWindow); + uiWindowMap_[obj] = uiWindow; + context->SetSessionInfo(sessionInfo); +#ifdef SUPPORT_GRAPHICS + context->SetWindow(uiWindow); +#endif // SUPPORT_GRAPHICS + return true; +} + +bool EtsAutoFillExtension::HandleAutoFillCreate(const AAFwk::Want &want, sptr sessionInfo) +{ + if (sessionInfo == nullptr || sessionInfo->sessionToken == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid sessionInfo"); + return false; + } + auto obj = sessionInfo->sessionToken; + std::shared_ptr sharedWant = std::make_shared(want); + if (uiWindowMap_.find(obj) != uiWindowMap_.end()) { + auto uiWindow = uiWindowMap_[obj]; + if (uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow"); + return false; + } + uiWindow->UpdateExtensionConfig(sharedWant); + return true; + } + return CreateNewWindow(sessionInfo, obj, sharedWant); +} + +void EtsAutoFillExtension::ForegroundWindow(const AAFwk::Want &want, sptr sessionInfo) +{ + if (sessionInfo == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo"); + return; + } + auto context = GetContext(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null context"); + return; + } + if (want.HasParameter(WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY)) { + isPopup_ = want.GetBoolParam(WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY, false); + } + + if (!HandleAutoFillCreate(want, sessionInfo)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "HandleAutoFillCreate failed"); + return; + } + auto obj = sessionInfo->sessionToken; + auto iter = uiWindowMap_.find(obj); + if (iter == uiWindowMap_.end()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "uiWindow not found for sessionToken"); + return; + } + auto& uiWindow = iter->second; + if (uiWindow) { + { + HITRACE_METER_NAME(HITRACE_TAG_APP, "Rosen::Window::show"); + uiWindow->Show(); + } + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "uiWindow show"); + foregroundWindows_.emplace(obj); + + RegisterTransferComponentDataListener(uiWindow); + AAFwk::WantParams wantParams; + wantParams.SetParam(WANT_PARAMS_AUTO_FILL_EVENT_KEY, AAFwk::Integer::Box( + static_cast(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_REMOVE_TIME_OUT))); + uiWindow->TransferExtensionData(wantParams); + } +} + +void EtsAutoFillExtension::BackgroundWindow(sptr sessionInfo) +{ + if (sessionInfo == nullptr || sessionInfo->sessionToken == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid sessionInfo"); + return; + } + auto obj = sessionInfo->sessionToken; + if (uiWindowMap_.find(obj) == uiWindowMap_.end()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "find ui window failed"); + return; + } + auto& uiWindow = uiWindowMap_[obj]; + if (uiWindow) { + uiWindow->Hide(); + foregroundWindows_.erase(obj); + } +} + +void EtsAutoFillExtension::DestroyWindow(sptr sessionInfo) +{ + if (sessionInfo == nullptr || sessionInfo->sessionToken == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid sessionInfo"); + return; + } + auto obj = sessionInfo->sessionToken; + if (uiWindowMap_.find(obj) == uiWindowMap_.end()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Wrong to find uiWindow"); + return; + } + if (contentSessions_.find(obj) != contentSessions_.end() && contentSessions_[obj] != nullptr) { + CallObjectMethod(false, "onSessionDestroy", ON_SESSION_DESTROY_METHOD_NAME, + static_cast(contentSessions_[obj])); + } + auto& uiWindow = uiWindowMap_[obj]; + if (uiWindow) { + uiWindow->Destroy(); + } + uiWindowMap_.erase(obj); + foregroundWindows_.erase(obj); + contentSessions_.erase(obj); + callbacks_.erase(obj); +} + +bool EtsAutoFillExtension::CallObjectMethod(bool withResult, const char *name, const char *signature, ...) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, std::string("CallObjectMethod:") + name); + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "CallObjectMethod %{public}s", name); + if (etsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "etsObj_ nullptr"); + return false; + } + + auto env = etsRuntime_.GetAniEnv(); + ani_status status = ANI_OK; + ani_method method = nullptr; + if ((status = env->Class_FindMethod(etsObj_->aniCls, name, signature, &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return false; + } + env->ResetError(); + if (withResult) { + ani_boolean res = ANI_FALSE; + va_list args; + va_start(args, signature); + if ((status = env->Object_CallMethod_Boolean(etsObj_->aniObj, method, &res, args)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + etsRuntime_.HandleUncaughtError(); + } + va_end(args); + return res; + } + va_list args; + va_start(args, signature); + if ((status = env->Object_CallMethod_Void_V(etsObj_->aniObj, method, args)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + etsRuntime_.HandleUncaughtError(); + return false; + } + va_end(args); + return false; +} + +void EtsAutoFillExtension::ProcessRequest(const AAFwk::Want &want, sptr sessionInfo, + sptr uiWindow, ani_object nativeContentSession) +{ + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_object request = EtsAutoFillExtensionUtil::WrapFillRequest(env, want); + if (request == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null request"); + return; + } + ani_object callback = nullptr; + auto cmdValue = want.GetIntParam(WANT_PARAMS_AUTO_FILL_CMD, 0); + if (cmdValue == AutoFillCommand::SAVE) { + callback = EtsSaveRequestCallback::CreateEtsSaveRequestCallback(env, sessionInfo, uiWindow); + CallObjectMethod(false, "onSaveRequest", ON_SAVE_REQUEST_METHOD_NAME, nativeContentSession, request, callback); + } else if (cmdValue == AutoFillCommand::FILL || cmdValue == AutoFillCommand::RELOAD_IN_MODAL) { + callback = EtsFillRequestCallback::CreateEtsFillRequestCallback(env, sessionInfo, uiWindow); + CallObjectMethod(false, "onFillRequest", ON_FILL_REQUEST_METHOD_NAME, nativeContentSession, request, callback); + } else { + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Invalid auto fill request type"); + return; + } + ani_ref callbackRef = nullptr; + ani_status status = ANI_OK; + if ((status = env->GlobalReference_Create(callback, &callbackRef)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return; + } + callbacks_.emplace(sessionInfo->sessionToken, callbackRef); +} + +void EtsAutoFillExtension::CallEtsOnRequest(const AAFwk::Want &want, sptr sessionInfo, + sptr uiWindow) +{ + if (sessionInfo == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo"); + return; + } + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + auto context = GetContext(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null context"); + return; + } + std::weak_ptr weakContext = context; + std::shared_ptr abilityResultListeners = nullptr; + std::shared_ptr etsUiExtContentSession = + std::make_shared(sessionInfo, uiWindow, weakContext, abilityResultListeners); + ani_object nativeContentSession = EtsUIExtensionContentSession::CreateEtsUIExtensionContentSession(env, + sessionInfo, uiWindow, weakContext, abilityResultListeners, etsUiExtContentSession); + if (nativeContentSession == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null session"); + return; + } + ani_ref ref = nullptr; + ani_status status = ANI_OK; + if ((status = env->GlobalReference_Create(nativeContentSession, &ref)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return; + } + contentSessions_.emplace(sessionInfo->sessionToken, ref); + ProcessRequest(want, sessionInfo, uiWindow, nativeContentSession); +} + +void EtsAutoFillExtension::RegisterTransferComponentDataListener(sptr uiWindow) +{ + if (uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow"); + return; + } + + auto handler = std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); + if (handler == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null handler"); + return; + } + std::weak_ptr weakPtr = std::static_pointer_cast(shared_from_this()); + uiWindow->RegisterTransferComponentDataListener([etsAutoFillExtensionWeakPtr = weakPtr, handler]( + const AAFwk::WantParams &wantParams) { + auto etsAutoFillExtensionPtr = etsAutoFillExtensionWeakPtr.lock(); + if (etsAutoFillExtensionPtr == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsAutoFillExtensionPtr"); + return; + } + handler->PostTask([etsAutoFillExtensionPtr, wantParams]() { + etsAutoFillExtensionPtr->UpdateRequest(wantParams); + }, "EtsAutoFillExtension:UpdateRequest"); + }); +} +} // namespace AbilityRuntime +} // namespace OHOS + +ETS_EXPORT extern "C" OHOS::AbilityRuntime::AutoFillExtension *OHOS_ETS_Auto_Fill_Extension_Create( + const std::unique_ptr &runtime) +{ + return OHOS::AbilityRuntime::EtsAutoFillExtension::Create(runtime); +} \ 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 0000000000000000000000000000000000000000..634c62e6621a347abf27c0a026ad3e4102a1ab1b --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_context.cpp @@ -0,0 +1,213 @@ +/* + * 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, + std::shared_ptr context) +{ + 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"); + delete etsAutoFillExtensionContext; + etsAutoFillExtensionContext = nullptr; + return nullptr; + } + if (!ContextUtil::SetNativeContextLong(env, contextObj, reinterpret_cast(workContext))) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "SetNativeContextLong failed"); + delete workContext; + workContext = nullptr; + delete etsAutoFillExtensionContext; + etsAutoFillExtensionContext = 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) +{ + 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) +{ + 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) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_status status = ANI_ERROR; + ani_ref etsCustomData = nullptr; + if ((status = env->Object_GetPropertyByName_Ref(customDataObj, "data", &etsCustomData)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_GetPropertyByName_Ref failed, status: %{public}d", status); + 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, + std::shared_ptr context) +{ + 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 + && status != ANI_ALREADY_BINDED) { + 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 && status != ANI_ALREADY_BINDED) { + 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_instance.cpp b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_instance.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f9fe453b9c4bed6355bd36e591e2a517cd159885 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_instance.cpp @@ -0,0 +1,54 @@ +/* + * 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_instance.h" + +#include +#include + +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" +#include "string_wrapper.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +const char *ETS_ANI_LIBNAME = "libauto_fill_extension_ani.z.so"; +const char *ETS_ANI_CREATE_FUNC = "OHOS_ETS_Auto_Fill_Extension_Create"; +using CreateETSAutoFillExtensionFunc = AutoFillExtension*(*)(const std::unique_ptr&); +CreateETSAutoFillExtensionFunc g_etsCreateFunc = nullptr; +} + +AutoFillExtension *CreateETSAutoFillExtension(const std::unique_ptr &runtime) +{ + if (g_etsCreateFunc != nullptr) { + return g_etsCreateFunc(runtime); + } + auto handle = dlopen(ETS_ANI_LIBNAME, RTLD_LAZY); + if (handle == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "dlopen failed %{public}s, %{public}s", ETS_ANI_LIBNAME, dlerror()); + return nullptr; + } + auto symbol = dlsym(handle, ETS_ANI_CREATE_FUNC); + if (symbol == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "dlsym failed %{public}s, %{public}s", ETS_ANI_CREATE_FUNC, dlerror()); + dlclose(handle); + return nullptr; + } + g_etsCreateFunc = reinterpret_cast(symbol); + return g_etsCreateFunc(runtime); +} +} // namespace AbilityRuntime +} // namespace OHOS \ 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 0000000000000000000000000000000000000000..a11be40a8a9a247fa0701c8b4002f1458fe5a2ed --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_util.cpp @@ -0,0 +1,614 @@ +/* + * 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 "ani_common_want.h" +#include "ani_enum_convert.h" +#include "hilog_tag_wrapper.h" +#include "want_params_wrapper.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *FILL_REQUEST_CLASS_NAME = "Lapplication/AutoFillRequest/FillRequestInner;"; +constexpr const char *UPDATE_REQUEST_CLASS_NAME = "Lapplication/AutoFillRequest/UpdateRequestInner;"; +constexpr const char *VIEW_DATA_CLASS_NAME = "Lapplication/ViewData/ViewDataImpl;"; +constexpr const char *ARRAY_CLASS_NAME = "Lescompat/Array;"; +constexpr const char *PAGE_NODE_INFO_CLASS_NAME = "Lapplication/PageNodeInfo/PageNodeInfoImpl;"; +constexpr const char *AUTO_FILL_RECT_CLASS_NAME = "Lapplication/AutoFillRect/AutoFillRectImpl;"; +constexpr const char *CUSTOM_DATA_CLASS_NAME = "Lapplication/CustomData/CustomDataInner;"; +constexpr const char *AUTO_FILL_TYPE_ENUM_NAME = "Lapplication/AutoFillType/AutoFillType;"; +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_TYPE = "type"; +constexpr const char *VIEW_DATA_PAGE_RECT = "pageRect"; +constexpr const char *CUSTOM_DATA_CUSTOM_DATA = "customData"; +constexpr const char *CUSTOM_DATA_DATA = "data"; +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 *WANT_PARAMS_VIEW_DATA = "ohos.ability.params.viewData"; +constexpr const char *WANT_PARAMS_CUSTOM_DATA = "ohos.ability.params.customData"; +constexpr const char *WANT_PARAMS_AUTO_FILL_TYPE_KEY = "ability.want.params.AutoFillType"; +constexpr const char *WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY = "ohos.ability.params.popupWindow"; +constexpr const char *WANT_PARAMS_IS_POPUP = "isPopup"; +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 + +ani_object EtsAutoFillExtensionUtil::WrapFillRequest(ani_env *env, const AAFwk::Want &want) +{ + ani_object etsObject = nullptr; + if (!CreateObject(env, etsObject, FILL_REQUEST_CLASS_NAME)) { + return nullptr; + } + return SetFillRequest(env, etsObject, want); +} + +ani_object EtsAutoFillExtensionUtil::WrapUpdateRequest(ani_env *env, const AAFwk::WantParams &wantParams) +{ + ani_object etsObject = nullptr; + if (!CreateObject(env, etsObject, UPDATE_REQUEST_CLASS_NAME)) { + return nullptr; + } + std::string viewDataString = wantParams.GetStringParam(WANT_PARAMS_VIEW_DATA); + if (viewDataString.empty()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty view data"); + return etsObject; + } + AbilityBase::ViewData viewData; + viewData.FromJsonString(viewDataString); + ani_object viewDataValue = WrapViewData(env, viewData); + ani_status status = ANI_ERROR; + if ((status = env->Object_SetPropertyByName_Ref(etsObject, VIEW_DATA_VIEW_DATA, viewDataValue)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + } + return etsObject; +} + +ani_object EtsAutoFillExtensionUtil::WrapViewData(ani_env *env, const AbilityBase::ViewData &viewData) +{ + ani_object etsObject = nullptr; + if (!CreateObject(env, etsObject, VIEW_DATA_CLASS_NAME)) { + return nullptr; + } + return SetViewData(env, etsObject, viewData); +} + +ani_object EtsAutoFillExtensionUtil::WrapPageNodeInfo(ani_env *env, const AbilityBase::PageNodeInfo &pageNodeInfo) +{ + ani_object etsObject = nullptr; + if (!CreateObject(env, etsObject, PAGE_NODE_INFO_CLASS_NAME)) { + return nullptr; + } + ani_status status = ANI_ERROR; + if ((status = env->Object_SetPropertyByName_Int(etsObject, PAGE_INFO_ID, + static_cast(pageNodeInfo.id))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return etsObject; + } + if ((status = env->Object_SetPropertyByName_Int(etsObject, PAGE_INFO_DEPTH, + static_cast(pageNodeInfo.depth))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return etsObject; + } + ani_enum_item autoFillTypeItem = nullptr; + AAFwk::AniEnumConvertUtil::EnumConvert_NativeToEts(env, AUTO_FILL_TYPE_ENUM_NAME, pageNodeInfo.autoFillType, + autoFillTypeItem); + if ((status = env->Object_SetPropertyByName_Ref(etsObject, PAGE_INFO_AUTOFILLTYPE, autoFillTypeItem)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return etsObject; + } + return SetPageNodeInfo(env, etsObject, pageNodeInfo); +} + +ani_object EtsAutoFillExtensionUtil::WrapRectData(ani_env *env, const AbilityBase::Rect &rect) +{ + ani_object etsObject = nullptr; + if (!CreateObject(env, etsObject, AUTO_FILL_RECT_CLASS_NAME)) { + return nullptr; + } + return SetRectData(env, etsObject, rect); +} + +ani_object EtsAutoFillExtensionUtil::WrapCustomData(ani_env *env, const AAFwk::WantParams ¶m) +{ + ani_object etsObject = nullptr; + if (!CreateObject(env, etsObject, CUSTOM_DATA_CLASS_NAME)) { + return nullptr; + } + ani_ref etsValue = AppExecFwk::WrapWantParams(env, param); + ani_status status = ANI_ERROR; + if ((status = env->Object_SetPropertyByName_Ref(etsObject, CUSTOM_DATA_DATA, etsValue)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + } + return etsObject; +} + +void EtsAutoFillExtensionUtil::UnwrapViewData(ani_env *env, const ani_object object, AbilityBase::ViewData &viewData) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_status status = ANI_ERROR; + ani_ref etsViewData = nullptr; + if ((status = env->Object_GetPropertyByName_Ref(object, VIEW_DATA_VIEW_DATA, &etsViewData)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_GetPropertyByName_Ref failed, status: %{public}d", status); + 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 pageNode = nullptr; + if ((status = env->Object_GetPropertyByName_Ref(static_cast(etsViewData), VIEW_DATA_PAGE_NODE_INFOS, + &pageNode)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_GetPropertyByName_Ref failed, status: %{public}d", status); + return; + } + if (pageNode != nullptr) { + ani_size length = 0; + if ((status = env->Array_GetLength(reinterpret_cast(pageNode), &length)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Array_GetLength failed, status: %{public}d", status); + return; + } + for (ani_size index = 0; index < length && index < PAGE_NODE_COUNT_MAX; index++) { + ani_ref etsNode = nullptr; + if ((status = env->Array_Get_Ref(reinterpret_cast(pageNode), index, &etsNode)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Array_Get_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 ((status = env->Object_GetPropertyByName_Ref(static_cast(etsViewData), VIEW_DATA_PAGE_RECT, + &etsPageRect)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_GetPropertyByName_Ref failed, status: %{public}d", status); + return; + } + if (etsPageRect != nullptr) { + UnwrapRectData(env, static_cast(etsPageRect), viewData.pageRect); + } +} + +void EtsAutoFillExtensionUtil::UnwrapPageNodeInfo(ani_env *env, const ani_object object, + AbilityBase::PageNodeInfo &node) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_status status = ANI_ERROR; + ani_int id = 0; + if ((status = env->Object_GetPropertyByName_Int(object, PAGE_INFO_ID, &id)) == ANI_OK) { + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "id:%{public}d", id); + node.id = id; + } + ani_int depth = 0; + if ((status = env->Object_GetPropertyByName_Int(object, PAGE_INFO_DEPTH, &depth)) == ANI_OK) { + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "depth:%{public}d", depth); + node.depth = depth; + } + ani_ref etsAutoFillType = nullptr; + if (AppExecFwk::GetRefProperty(env, object, PAGE_INFO_AUTOFILLTYPE, etsAutoFillType) && etsAutoFillType) { + int32_t autoFillType = 0; + AAFwk::AniEnumConvertUtil::EnumConvert_EtsToNative(env, static_cast(etsAutoFillType), + autoFillType); + TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "autoFillType:%{public}d", autoFillType); + node.autoFillType = static_cast(autoFillType); + } + UnwrapPageNodeInfoString(env, object, node); + ani_boolean enableAutoFill = ANI_FALSE; + if ((status = env->Object_GetPropertyByName_Boolean(object, PAGE_INFO_ENABLEAUTOFILL, &enableAutoFill)) == + ANI_OK) { + node.enableAutoFill = static_cast(enableAutoFill); + } + ani_ref etsRect = nullptr; + if ((status = env->Object_GetPropertyByName_Ref(object, PAGE_INFO_PAGE_NODE_RECT, &etsRect)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Object_GetPropertyByName_Ref failed, status: %{public}d", status); + return; + } + if (etsRect != nullptr) { + UnwrapRectData(env, static_cast(etsRect), node.rect); + } + ani_boolean isFocus = ANI_FALSE; + if ((status = env->Object_GetPropertyByName_Boolean(object, PAGE_INFO_IS_FOCUS, &isFocus)) == ANI_OK) { + node.isFocus = static_cast(isFocus); + } +} + +void EtsAutoFillExtensionUtil::UnwrapRectData(ani_env *env, const ani_object object, AbilityBase::Rect &rect) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_status status = ANI_ERROR; + ani_double position = 0.0; + if ((status = env->Object_GetPropertyByName_Double(object, RECT_POSITION_LEFT, &position)) == ANI_OK) { + rect.left = position; + } + if ((status = env->Object_GetPropertyByName_Double(object, RECT_POSITION_TOP, &position)) == ANI_OK) { + rect.top = position; + } + if ((status = env->Object_GetPropertyByName_Double(object, RECT_WIDTH, &position)) == ANI_OK) { + rect.width = position; + } + if ((status = env->Object_GetPropertyByName_Double(object, RECT_HEIGHT, &position)) == ANI_OK) { + rect.height = position; + } +} + +void EtsAutoFillExtensionUtil::UnwrapFillResponse(ani_env *env, const ani_object object, FillResponse &response) +{ + UnwrapViewData(env, object, response.viewData); +} + +void EtsAutoFillExtensionUtil::UnwrapPopupSize(ani_env *env, const ani_object object, PopupSize &popupSize) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_status status = ANI_ERROR; + ani_double width = 0.0; + if ((status = env->Object_GetPropertyByName_Double(object, RECT_WIDTH, &width)) == ANI_OK) { + popupSize.width = width; + } + ani_double height = 0.0; + if ((status = env->Object_GetPropertyByName_Double(object, RECT_HEIGHT, &height)) == ANI_OK) { + popupSize.height = height; + } +} + +bool EtsAutoFillExtensionUtil::CreateObject(ani_env *env, ani_object &object, const std::string &className) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return false; + } + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass(className.c_str(), &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status : %{public}d", status); + return false; + } + if (cls == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null cls"); + return false; + } + ani_method method = nullptr; + if ((status = env->Class_FindMethod(cls, "", ":V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status : %{public}d", status); + return false; + } + if (method == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null method"); + return false; + } + if ((status = env->Object_New(cls, method, &object)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status : %{public}d", status); + return false; + } + if (object == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null object"); + return false; + } + return true; +} + +ani_object EtsAutoFillExtensionUtil::SetFillRequest(ani_env *env, ani_object object, const AAFwk::Want &want) +{ + ani_status status = ANI_ERROR; + if (want.HasParameter(WANT_PARAMS_AUTO_FILL_TYPE_KEY)) { + auto type = want.GetIntParam(WANT_PARAMS_AUTO_FILL_TYPE_KEY, -1); + ani_enum_item typeItem = nullptr; + AAFwk::AniEnumConvertUtil::EnumConvert_NativeToEts(env, AUTO_FILL_TYPE_ENUM_NAME, type, typeItem); + if ((status = env->Object_SetPropertyByName_Ref(object, VIEW_DATA_TYPE, typeItem)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + } + if (want.HasParameter(WANT_PARAMS_VIEW_DATA)) { + std::string viewDataString = want.GetStringParam(WANT_PARAMS_VIEW_DATA); + if (viewDataString.empty()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty view data"); + return object; + } + AbilityBase::ViewData viewData; + viewData.FromJsonString(viewDataString); + ani_object viewDataValue = WrapViewData(env, viewData); + if ((status = env->Object_SetPropertyByName_Ref(object, VIEW_DATA_VIEW_DATA, viewDataValue)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + } + if (want.HasParameter(WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY)) { + auto isPopup = want.GetBoolParam(WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY, false); + if ((status = env->Object_SetPropertyByName_Boolean(object, WANT_PARAMS_IS_POPUP, isPopup)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + } + if (want.HasParameter(WANT_PARAMS_CUSTOM_DATA)) { + std::string customDataString = want.GetStringParam(WANT_PARAMS_CUSTOM_DATA); + if (customDataString.empty()) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty custom data"); + return object; + } + if (!AAFwk::WantParamWrapper::ValidateStr(customDataString)) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "invalid Custom data string"); + return object; + } + AAFwk::WantParams param = AAFwk::WantParamWrapper::ParseWantParams(customDataString); + ani_object customValue = WrapCustomData(env, param); + if ((status = env->Object_SetPropertyByName_Ref(object, CUSTOM_DATA_CUSTOM_DATA, customValue)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + } + } + return object; +} + +ani_object EtsAutoFillExtensionUtil::SetViewData(ani_env *env, ani_object object, + const AbilityBase::ViewData &viewData) +{ + ani_status status = ANI_ERROR; + if ((status = env->Object_SetPropertyByName_Ref(object, VIEW_DATA_BUNDLE_NAME, + AppExecFwk::GetAniString(env, viewData.bundleName))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Ref(object, VIEW_DATA_ABILITY_NAME, + AppExecFwk::GetAniString(env, viewData.abilityName))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Ref(object, VIEW_DATA_MODULE_NAME, + AppExecFwk::GetAniString(env, viewData.moduleName))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Ref(object, VIEW_DATA_PAGEURL, + AppExecFwk::GetAniString(env, viewData.pageUrl))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Boolean(object, VIEW_DATA_USER_SELECTED, + viewData.isUserSelected)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Boolean(object, VIEW_DATA_OTHER_ACCOUNT, + viewData.isOtherAccount)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + ani_object arrayObj = nullptr; + SetViewDataArray(env, arrayObj, viewData); + ani_object etsRectData = WrapRectData(env, viewData.pageRect); + if ((status = env->Object_SetPropertyByName_Ref(object, VIEW_DATA_PAGE_RECT, etsRectData)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Ref(object, VIEW_DATA_PAGE_NODE_INFOS, arrayObj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + } + return object; +} + +void EtsAutoFillExtensionUtil::SetViewDataArray(ani_env *env, ani_object &object, + const AbilityBase::ViewData &viewData) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass(ARRAY_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status : %{public}d", status); + return; + } + if (cls == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null cls"); + return; + } + ani_method method = nullptr; + if ((status = env->Class_FindMethod(cls, "", "I:V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status : %{public}d", status); + return; + } + if (method == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null method"); + return; + } + if ((status = env->Object_New(cls, method, &object, viewData.nodes.size())) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status : %{public}d", status); + return; + } + if (object == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null object"); + return; + } + ani_object etsSubValue = nullptr; + ani_size index = 0; + for (auto &element : viewData.nodes) { + etsSubValue = WrapPageNodeInfo(env, element); + if (etsSubValue == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null etsSubValue"); + break; + } + if ((status = env->Object_CallMethodByName_Void(object, "$_set", "ILstd/core/Object;:V", index, + etsSubValue)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status : %{public}d", status); + break; + } + index++; + } +} + +ani_object EtsAutoFillExtensionUtil::SetPageNodeInfo(ani_env *env, ani_object object, + const AbilityBase::PageNodeInfo &pageNodeInfo) +{ + ani_status status = ANI_ERROR; + if ((status = env->Object_SetPropertyByName_Ref(object, PAGE_INFO_TAG, + AppExecFwk::GetAniString(env, pageNodeInfo.tag))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Ref(object, PAGE_INFO_VALUE, + AppExecFwk::GetAniString(env, pageNodeInfo.value))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Ref(object, PAGE_INFO_PASSWORDRULES, + AppExecFwk::GetAniString(env, pageNodeInfo.passwordRules))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Ref(object, PAGE_INFO_PLACEHOLDER, + AppExecFwk::GetAniString(env, pageNodeInfo.placeholder))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Ref(object, PAGE_INFO_META_DATA, + AppExecFwk::GetAniString(env, pageNodeInfo.metadata))) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Boolean(object, PAGE_INFO_ENABLEAUTOFILL, + pageNodeInfo.enableAutoFill)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + ani_object etsRectData = WrapRectData(env, pageNodeInfo.rect); + if ((status = env->Object_SetPropertyByName_Ref(object, PAGE_INFO_PAGE_NODE_RECT, etsRectData)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Boolean(object, PAGE_INFO_IS_FOCUS, + pageNodeInfo.isFocus)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + } + return object; +} + +ani_object EtsAutoFillExtensionUtil::SetRectData(ani_env *env, ani_object object, const AbilityBase::Rect &rect) +{ + ani_status status = ANI_ERROR; + if ((status = env->Object_SetPropertyByName_Double(object, RECT_POSITION_LEFT, rect.left)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Double(object, RECT_POSITION_TOP, rect.top)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Double(object, RECT_WIDTH, rect.width)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + return object; + } + if ((status = env->Object_SetPropertyByName_Double(object, RECT_HEIGHT, rect.height)) != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "status: %{public}d", status); + } + return object; +} + +void EtsAutoFillExtensionUtil::UnwrapViewDataString(ani_env *env, const ani_object object, + AbilityBase::ViewData &viewData) +{ + std::string bundleName = ""; + if (AppExecFwk::GetStringProperty(env, object, VIEW_DATA_BUNDLE_NAME, bundleName)) { + viewData.bundleName = bundleName; + } + std::string moduleName = ""; + if (AppExecFwk::GetStringProperty(env, object, VIEW_DATA_MODULE_NAME, moduleName)) { + viewData.moduleName = moduleName; + } + std::string abilityName = ""; + if (AppExecFwk::GetStringProperty(env, object, VIEW_DATA_ABILITY_NAME, abilityName)) { + viewData.abilityName = abilityName; + } + std::string pageUrl = ""; + if (AppExecFwk::GetStringProperty(env, object, VIEW_DATA_PAGEURL, pageUrl)) { + viewData.pageUrl = pageUrl; + } +} + +void EtsAutoFillExtensionUtil::UnwrapViewDataBoolean(ani_env *env, const ani_object object, + AbilityBase::ViewData &viewData) +{ + ani_status status = ANI_ERROR; + ani_boolean isUserSelected = ANI_FALSE; + if ((status = env->Object_GetPropertyByName_Boolean(object, VIEW_DATA_USER_SELECTED, &isUserSelected)) == ANI_OK) { + viewData.isUserSelected = static_cast(isUserSelected); + } + ani_boolean isOtherAccount = ANI_FALSE; + if ((status = env->Object_GetPropertyByName_Boolean(object, VIEW_DATA_OTHER_ACCOUNT, &isOtherAccount)) == ANI_OK) { + viewData.isOtherAccount = static_cast(isOtherAccount); + } +} + +void EtsAutoFillExtensionUtil::UnwrapPageNodeInfoString(ani_env *env, const ani_object object, + AbilityBase::PageNodeInfo &node) +{ + std::string tag = ""; + if (AppExecFwk::GetStringProperty(env, object, PAGE_INFO_TAG, tag)) { + node.tag = tag; + } + std::string value = ""; + if (AppExecFwk::GetStringProperty(env, object, PAGE_INFO_VALUE, value)) { + node.value = value; + } + std::string passwordRules = ""; + if (AppExecFwk::GetStringProperty(env, object, PAGE_INFO_PASSWORDRULES, passwordRules)) { + node.passwordRules = passwordRules; + } + std::string placeholder = ""; + if (AppExecFwk::GetStringProperty(env, object, PAGE_INFO_PLACEHOLDER, placeholder)) { + node.placeholder = placeholder; + } + std::string metadata = ""; + if (AppExecFwk::GetStringProperty(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 0000000000000000000000000000000000000000..3c3889884235297c3d2b9ece9e3427e3831c3e78 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_fill_request_callback.cpp @@ -0,0 +1,357 @@ +/* + * 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 "ani_enum_convert.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 *ERROR_MSG_PARAMETER_INVALID = + "The storeld can consist of only letters, digits, and underscores(_), and cannot exceed 128 characters."; +constexpr const char *FILL_REQUEST_CALL_BACK_CLASS_NAME = "Lapplication/AutoFillRequest/FillRequestCallbackInner;"; +constexpr const char *CLEANER_CLASS = "Lapplication/AutoFillRequest/Cleaner;"; +} + +EtsFillRequestCallback::EtsFillRequestCallback( + sptr sessionInfo, sptr uiWindow) + : sessionInfo_(sessionInfo), uiWindow_(uiWindow) +{} + +ani_object EtsFillRequestCallback::SetEtsFillRequestCallback(ani_env *env, sptr sessionInfo, + sptr uiWindow) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + 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) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "parse fillContent failed"); + EtsErrorUtil::ThrowError(env, static_cast(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), + ERROR_MSG_PARAMETER_INVALID); + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED_INVALID_PARAM, ""); + return; + } + std::string jsonString = ""; + 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) +{ + 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::GetRefProperty(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; + } + etsValue = nullptr; + if (AppExecFwk::GetRefProperty(env, autoFillPopupConfigObj, CONFIG_POPUP_PLACEMENT, etsValue) && etsValue) { + int32_t popupPlacement = 0; + AAFwk::AniEnumConvertUtil::EnumConvert_EtsToNative(env, static_cast(etsValue), 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) +{ + 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, + sptr sessionInfo, sptr uiWindow) +{ + if (env == nullptr || sessionInfo == nullptr || uiWindow == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env, 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/AutoFillPopupConfig/AutoFillPopupConfig;:V", + reinterpret_cast(EtsFillRequestCallback::FillRequestAutoFillPopupConfig) }, + }; + if ((status = env->Class_BindNativeMethods(cls, functions.data(), functions.size())) != ANI_OK + && status != ANI_ALREADY_BINDED) { + 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 && status != ANI_ALREADY_BINDED) { + 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 0000000000000000000000000000000000000000..3330d7fa82837949bb7aad40107d69b284c34ff2 --- /dev/null +++ b/frameworks/ets/ani/auto_fill_extension_ability/src/ets_save_request_callback.cpp @@ -0,0 +1,221 @@ +/* + * 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( + sptr sessionInfo, sptr uiWindow) + : sessionInfo_(sessionInfo), uiWindow_(uiWindow) +{} + +ani_object EtsSaveRequestCallback::SetEtsSaveRequestCallback(ani_env *env, sptr sessionInfo, + sptr uiWindow) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env"); + return; + } + SendResultCodeAndViewData(EtsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED); +} + +void EtsSaveRequestCallback::SendResultCodeAndViewData(const EtsAutoFillExtensionUtil::AutoFillResultCode &resultCode) +{ + 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, + sptr sessionInfo, sptr uiWindow) +{ + 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 + && status != ANI_ALREADY_BINDED) { + 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 && status != ANI_ALREADY_BINDED) { + 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/ani/auto_fill_manager/src/ets_auto_save_request_callback.cpp b/frameworks/ets/ani/auto_fill_manager/src/ets_auto_save_request_callback.cpp index 62f33b5a13db0d3e5acc92853a4d72e5ca529882..d8bd91518582e878900ad34accf3d9e1a3e8fdf0 100644 --- a/frameworks/ets/ani/auto_fill_manager/src/ets_auto_save_request_callback.cpp +++ b/frameworks/ets/ani/auto_fill_manager/src/ets_auto_save_request_callback.cpp @@ -15,11 +15,13 @@ #include "ets_auto_save_request_callback.h" +#include "ani_common_util.h" #include "hilog_tag_wrapper.h" namespace OHOS { namespace AutoFillManagerEts { namespace { +constexpr int32_t ARGC_ZERO = 0; const std::string METHOD_ON_SAVE_REQUEST_SUCCESS = "onSuccess"; const std::string METHOD_ON_SAVE_REQUEST_FAILED = "onFailure"; } // namespace @@ -95,11 +97,22 @@ void EtsAutoSaveRequestCallback::ETSCallFunction(const std::string &methodName) return; } - ani_status status = ANI_OK; - status = env->Object_CallMethodByName_Void(reinterpret_cast(callback_->aniRef), methodName.c_str(), - nullptr); + ani_status status = ANI_ERROR; + ani_ref funRef; + status = env->Object_GetPropertyByName_Ref(reinterpret_cast(callback_->aniRef), methodName.c_str(), + &funRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::AUTOFILLMGR, "Object_GetPropertyByName_Ref failed, status: %{public}d", status); + return; + } + if (!AppExecFwk::IsValidProperty(env, funRef)) { + TAG_LOGI(AAFwkTag::AUTOFILLMGR, "invalid property"); + return; + } + ani_ref result; + status = env->FunctionalObject_Call(reinterpret_cast(funRef), ARGC_ZERO, nullptr, &result); if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::AUTOFILLMGR, "Object_CallMethodByName_Void failed, status: %{public}d", status); + TAG_LOGE(AAFwkTag::AUTOFILLMGR, "FunctionalObject_Call failed, status: %{public}d", status); } } diff --git a/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_content_session.cpp b/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_content_session.cpp index 197078cfbd39c9ef5be60049d4f197b5c26787ca..2637bd520757b1992382007dcee0cebe4eb7f0b8 100644 --- a/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_content_session.cpp +++ b/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_content_session.cpp @@ -262,7 +262,8 @@ bool EtsUIExtensionContentSession::BindNativePtrCleaner(ani_env *env) std::array methods = { ani_native_function { "clean", nullptr, reinterpret_cast(EtsUIExtensionContentSession::Clean) }, }; - if (ANI_OK != env->Class_BindNativeMethods(cleanerCls, methods.data(), methods.size())) { + if (ANI_OK != (status = env->Class_BindNativeMethods(cleanerCls, methods.data(), methods.size())) + && status != ANI_ALREADY_BINDED) { TAG_LOGE(AAFwkTag::UI_EXT, "status: %{public}d", status); return false; }; @@ -296,7 +297,8 @@ ani_status EtsUIExtensionContentSession::BindNativeMethod(ani_env *env, ani_clas reinterpret_cast(EtsUIExtensionContentSession::NativeSetWindowPrivacyMode)} }; ani_status status = ANI_ERROR; - if ((status = env->Class_BindNativeMethods(cls, methods.data(), methods.size())) != ANI_OK) { + if ((status = env->Class_BindNativeMethods(cls, methods.data(), methods.size())) != ANI_OK + && status != ANI_ALREADY_BINDED) { TAG_LOGE(AAFwkTag::UI_EXT, "status: %{public}d", status); return status; } diff --git a/frameworks/ets/ets/@ohos.app.ability.AutoFillExtensionAbility.ets b/frameworks/ets/ets/@ohos.app.ability.AutoFillExtensionAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..a8392b8db0eeca515d3ef14d168f758f35c91d23 --- /dev/null +++ b/frameworks/ets/ets/@ohos.app.ability.AutoFillExtensionAbility.ets @@ -0,0 +1,67 @@ +/* + * 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 ExtensionAbility from '@ohos.app.ability.ExtensionAbility'; +import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; +import AutoFillExtensionContext from 'application.AutoFillExtensionContext'; +import { FillRequest, SaveRequest, UpdateRequest, FillRequestCallback, SaveRequestCallback } from 'application.AutoFillRequest'; +import { AbilityUtils } from './utils/AbilityUtils'; + +export default class AutoFillExtensionAbility extends ExtensionAbility { + context!: AutoFillExtensionContext; + + onCreate(): void { + + } + + onFillRequest(session: UIExtensionContentSession, request: FillRequest, callback: FillRequestCallback): void { + + } + + onSaveRequest(session: UIExtensionContentSession, request: SaveRequest, callback: SaveRequestCallback): void { + + } + + onUpdateRequest(request: UpdateRequest): void { + + } + + onSessionDestroy(session: UIExtensionContentSession): void { + + } + + onForeground(): void { + + } + + onBackground(): void { + + } + + private destroyCallbackPoint: long; + private native nativeOnDestroyCallback(): void; + private callOnDestroy(): boolean { + let p = this.onDestroy(); + if (p instanceof Promise) { + p.then(() => this.nativeOnDestroyCallback()); + return true; + } + return false; + } + + onDestroy(): Promise | undefined { + return undefined; + } +} \ No newline at end of file diff --git a/frameworks/ets/ets/@ohos.app.ability.autoFillManager.ets b/frameworks/ets/ets/@ohos.app.ability.autoFillManager.ets index a11e43fde9505892b00f31f70ec1301bdffb2e13..d936fab0edf5766ef5c336eef0b56c5e2634f202 100644 --- a/frameworks/ets/ets/@ohos.app.ability.autoFillManager.ets +++ b/frameworks/ets/ets/@ohos.app.ability.autoFillManager.ets @@ -14,18 +14,33 @@ */ import { UIContext } from '@ohos.arkui.UIContext'; +import _ViewData from 'application.ViewData'; +import _PageNodeInfo from 'application.PageNodeInfo'; +import { FillRequest as _FillRequest, SaveRequest as _SaveRequest} from 'application.AutoFillRequest'; +import { UpdateRequest as _UpdateRequest, FillResponse as _FillResponse} from 'application.AutoFillRequest'; +import { FillRequestCallback as _FillRequestCallback } from 'application.AutoFillRequest'; +import { SaveRequestCallback as _SaveRequestCallback } from 'application.AutoFillRequest'; +import _CustomData from 'application.CustomData'; +import _AutoFillRect from 'application.AutoFillRect'; +import _AutoFillPopupConfig from 'application.AutoFillPopupConfig'; +import { PopupSize as _PopupSize } from 'application.AutoFillPopupConfig'; +import { AutoFillType as _AutoFillType } from 'application.AutoFillType'; +import { PopupPlacement as _PopupPlacement } from 'application.AutoFillPopupConfig'; namespace autoFillManager { + export type OnSuccessFn = () => void; + export type OnFailureFn = () => void; + loadLibrary("ability_auto_fill_manager_ani_kit.z"); export interface AutoSaveCallback { - onSuccess(): void; - onFailure(): void; + onSuccess: OnSuccessFn; + onFailure: OnFailureFn; } class AutoSaveCallbackInner implements AutoSaveCallback { - public onSuccess() {}; - public onFailure() {}; + onSuccess: OnSuccessFn = () => {}; + onFailure: OnFailureFn = () => {}; } export native function requestAutoSaveWithScope(callback?: AutoSaveCallback): void; @@ -34,6 +49,21 @@ namespace autoFillManager { requestAutoSaveWithScope(callback); }); } + + export type ViewData = _ViewData; + export type PageNodeInfo = _PageNodeInfo; + export type AutoFillType = _AutoFillType; + export type FillRequest = _FillRequest; + export type SaveRequest = _SaveRequest; + export type UpdateRequest = _UpdateRequest; + export type FillResponse = _FillResponse; + export type FillRequestCallback = _FillRequestCallback; + export type SaveRequestCallback = _SaveRequestCallback; + export type CustomData = _CustomData; + export type AutoFillRect = _AutoFillRect; + export type AutoFillPopupConfig = _AutoFillPopupConfig; + export type PopupSize = _PopupSize; + export type PopupPlacement = _PopupPlacement; } export default autoFillManager; diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index 6f0d1a22e0a540d61195c81e515734ebd52779c7..10d33f34fc1da30fb115bac03d8332ebc3ee4d1c 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" ] @@ -415,6 +447,22 @@ ohos_prebuilt_etc("ability_runtime_app_manager_abc_etc") { deps = [ ":ability_runtime_app_manager_abc" ] } +generate_static_abc("ability_runtime_auto_fill_extension_ability_abc") { + base_url = "./" + files = [ "./@ohos.app.ability.AutoFillExtensionAbility.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_auto_fill_extension_ability_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_auto_fill_extension_ability_abc_etc") { + source = "$target_out_dir/ability_runtime_auto_fill_extension_ability_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_auto_fill_extension_ability_abc" ] +} + generate_static_abc("ability_runtime_auto_fill_manager_abc") { base_url = "./" files = [ "./@ohos.app.ability.autoFillManager.ets" ] @@ -980,6 +1028,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" ] @@ -1329,7 +1441,12 @@ 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_ability_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", @@ -1362,11 +1479,13 @@ 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_running_multi_instance_info_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 0000000000000000000000000000000000000000..39f06b3b4150b233b1873782361a53bc367d456b --- /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 CustomData from 'application.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 0000000000000000000000000000000000000000..980aa45b94b123befc7616b2c3b1267cf67acd2b --- /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 0000000000000000000000000000000000000000..2f8a653358adbb801d57e9cf98566afa72243467 --- /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 0000000000000000000000000000000000000000..bfea6da065d345e9d3264b074a3400dcf2ae4d77 --- /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 CustomData from 'application.CustomData'; +import AutoFillPopupConfig from 'application.AutoFillPopupConfig'; +import ViewData from 'application.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 0000000000000000000000000000000000000000..9bb9fa97efc28b755064bbac7baa2d9f39552660 --- /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 AutoFillRect from 'application.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 = {left: 0.0, top: 0.0, width: 0.0, height: 0.0}; + 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 0000000000000000000000000000000000000000..df7f66280c59393c019c32b6ba60ceeb7f9fb1d6 --- /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 'application.PageNodeInfo'; +import AutoFillRect from 'application.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 = {left: 0.0, top: 0.0, width: 0.0, height: 0.0}; + 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 6f711db1d1f21b60144e634a3fe0e13ad73ce6e1..3af2c87a2e7ee179ca15a8397be05b05c1dd300f 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -2911,6 +2911,7 @@ config("auto_fill_extension_config") { "${ability_runtime_path}/interfaces/kits/native/ability/native/ability_runtime", "${ability_runtime_path}/interfaces/kits/native/ability/native/auto_fill_extension_ability", "${ability_runtime_path}/interfaces/kits/native/ability/native/ui_extension_base", + "${ability_runtime_path}/frameworks/ets/ani/auto_fill_extension_ability/include", ] } @@ -2957,6 +2958,7 @@ ohos_shared_library("auto_fill_extension") { "${ability_runtime_native_path}/ability/native/auto_fill_extension_ability/js_auto_fill_extension_util.cpp", "${ability_runtime_native_path}/ability/native/auto_fill_extension_ability/js_fill_request_callback.cpp", "${ability_runtime_native_path}/ability/native/auto_fill_extension_ability/js_save_request_callback.cpp", + "${ability_runtime_path}/frameworks/ets/ani/auto_fill_extension_ability/src/ets_auto_fill_extension_instance.cpp", ] } @@ -2968,6 +2970,69 @@ 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/ui_extension_ability/include", + "${ability_runtime_path}/frameworks/ets/ani/enum_convert", + "${ability_runtime_path}/frameworks/ets/ani/auto_fill_extension_ability/include", + ] + + public_configs = [ ":auto_fill_extension_config" ] + + sources = [] + + deps = [ + ":abilitykit_native", + ":auto_fill_extension", + ":ui_extension", + ":ui_extension_ani", + "${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", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/ability:ability_context_native", + "${ability_runtime_native_path}/appkit:app_context", + ] + + external_deps = [ + "ability_base:session_info", + "ability_base:view_data", + "ability_base:want", + "access_token:libtokenid_sdk", + "hilog:libhilog", + "runtime_core:ani", + "hitrace:hitrace_meter", + "window_manager:embeddablewindowstageani_kit", + + ] + + 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_auto_fill_extension.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 diff --git a/frameworks/native/ability/native/auto_fill_extension_ability/auto_fill_extension.cpp b/frameworks/native/ability/native/auto_fill_extension_ability/auto_fill_extension.cpp index 6a8108d6dffa423d43b07ad6db48d7e3319a5bd9..b816d3b7ba242e10ba60d30cf772dcdb073ba6cc 100644 --- a/frameworks/native/ability/native/auto_fill_extension_ability/auto_fill_extension.cpp +++ b/frameworks/native/ability/native/auto_fill_extension_ability/auto_fill_extension.cpp @@ -16,6 +16,7 @@ #include "auto_fill_extension.h" #include "auto_fill_extension_context.h" +#include "ets_auto_fill_extension_instance.h" #include "hilog_tag_wrapper.h" #include "js_auto_fill_extension.h" #include "runtime.h" @@ -31,6 +32,8 @@ AutoFillExtension *AutoFillExtension::Create(const std::unique_ptr &run switch (runtime->GetLanguage()) { case Runtime::Language::JS: return JsAutoFillExtension::Create(runtime); + case Runtime::Language::ETS: + return CreateETSAutoFillExtension(runtime); default: return new AutoFillExtension(); }