From eb1278f1a3a31a6cdfa7fa3aa5f2a0e6d5c460a9 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Thu, 15 Dec 2022 17:30:00 +1100 Subject: [PATCH 01/17] Support TextInputAction Signed-off-by: swan.seo --- .../tizen/channels/text_input_channel.cc | 1 + .../tizen/tizen_input_method_context.cc | 26 +++++++++++++++++++ .../tizen/tizen_input_method_context.h | 2 ++ 3 files changed, 29 insertions(+) diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 154d867..d4db587 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -167,6 +167,7 @@ void TextInputChannel::HandleMethodCall( if (input_action_iter != client_config.MemberEnd() && input_action_iter->value.IsString()) { input_action_ = input_action_iter->value.GetString(); + input_method_context_->SetInputAction(input_action_); } text_capitalization_ = ""; diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index 0c94620..10e0910 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -273,6 +273,32 @@ bool TizenInputMethodContext::IsInputPanelShown() { return state == ECORE_IMF_INPUT_PANEL_STATE_SHOW; } +void TizenInputMethodContext::SetInputAction(const std::string& input_action) { + FT_ASSERT(imf_context_); + Ecore_IMF_Input_Panel_Return_Key_Type return_key_type = + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT; + + // Not support : none, previous, continueAction, route, emergencycall, newline + if (input_action == "TextInputAction.unspecified") { + return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT; + } else if (input_action == "TextInputAction.done") { + return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE; + } else if (input_action == "TextInputAction.go") { + return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO; + } else if (input_action == "TextInputAction.join") { + return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN; + } else if (input_action == "TextInputAction.next") { + return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT; + } else if (input_action == "TextInputAction.search") { + return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH; + } else if (input_action == "TextInputAction.send") { + return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND; + } + + ecore_imf_context_input_panel_return_key_type_set(imf_context_, + return_key_type); +} + void TizenInputMethodContext::SetInputPanelLayout( const std::string& input_type) { FT_ASSERT(imf_context_); diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index c241f90..abe1cc9 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -57,6 +57,8 @@ class TizenInputMethodContext { bool IsInputPanelShown(); + void SetInputAction(const std::string& input_action); + void SetInputPanelLayout(const std::string& layout); void SetInputPanelLayoutVariation(bool is_signed, bool is_decimal); From 116154b3fcef05c4d9fd8a24c997d008f37a9637 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Thu, 15 Dec 2022 18:45:08 +1100 Subject: [PATCH 02/17] Support TextEnableSuggestions Signed-off-by: swan.seo --- .../platform/tizen/channels/text_input_channel.cc | 10 ++++++++++ .../shell/platform/tizen/tizen_input_method_context.cc | 7 +++++++ .../shell/platform/tizen/tizen_input_method_context.h | 2 ++ 3 files changed, 19 insertions(+) diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index d4db587..0003094 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -25,6 +25,7 @@ constexpr char kUpdateEditingStateMethod[] = constexpr char kPerformActionMethod[] = "TextInputClient.performAction"; constexpr char kSetPlatformViewClient[] = "TextInput.setPlatformViewClient"; constexpr char kTextCapitalization[] = "textCapitalization"; +constexpr char kTextEnableSuggestions[] = "enableSuggestions"; constexpr char kTextInputAction[] = "inputAction"; constexpr char kTextInputType[] = "inputType"; constexpr char kTextInputTypeName[] = "name"; @@ -162,6 +163,15 @@ void TextInputChannel::HandleMethodCall( } client_id_ = client_id_json.GetInt(); + + auto enable_suggestions_iter = + client_config.FindMember(kTextEnableSuggestions); + if (enable_suggestions_iter != client_config.MemberEnd() && + enable_suggestions_iter->value.IsBool()) { + bool enable = enable_suggestions_iter->value.GetBool(); + input_method_context_->SetEnableSuggestions(enable); + } + input_action_ = ""; auto input_action_iter = client_config.FindMember(kTextInputAction); if (input_action_iter != client_config.MemberEnd() && diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index 10e0910..a4e2a5f 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -273,6 +273,13 @@ bool TizenInputMethodContext::IsInputPanelShown() { return state == ECORE_IMF_INPUT_PANEL_STATE_SHOW; } +void TizenInputMethodContext::SetEnableSuggestions(bool enable) { + FT_ASSERT(imf_context_); + + ecore_imf_context_prediction_allow_set(imf_context_, + enable ? EINA_TRUE : EINA_FALSE); +} + void TizenInputMethodContext::SetInputAction(const std::string& input_action) { FT_ASSERT(imf_context_); Ecore_IMF_Input_Panel_Return_Key_Type return_key_type = diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index abe1cc9..81abed6 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -57,6 +57,8 @@ class TizenInputMethodContext { bool IsInputPanelShown(); + void SetEnableSuggestions(bool enable); + void SetInputAction(const std::string& input_action); void SetInputPanelLayout(const std::string& layout); From c959aa0dd0a828377c4e0600e11c4b0eca38e3eb Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Wed, 1 Feb 2023 17:46:11 +1100 Subject: [PATCH 03/17] Add packages related to autofill --- tools/generate_sysroot.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/generate_sysroot.py b/tools/generate_sysroot.py index 9e9be17..ed12310 100755 --- a/tools/generate_sysroot.py +++ b/tools/generate_sysroot.py @@ -43,6 +43,10 @@ 'capi-system-system-settings-devel', 'capi-ui-efl-util', 'capi-ui-efl-util-devel', + 'capi-ui-autofill', + 'capi-ui-autofill-devel', + 'capi-ui-autofill-common', + 'capi-ui-autofill-common-devel', 'cbhm', 'cbhm-devel', 'coregl', From ff9486d0d74f690fd20c0098924340c283aa4154 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Wed, 1 Feb 2023 17:55:54 +1100 Subject: [PATCH 04/17] Implement TizenAutofill --- .../tizen/channels/text_input_channel.cc | 39 ++++ .../tizen/channels/text_input_channel.h | 5 + .../shell/platform/tizen/tizen_autofill.cc | 187 ++++++++++++++++++ flutter/shell/platform/tizen/tizen_autofill.h | 78 ++++++++ .../tizen/tizen_input_method_context.cc | 5 +- .../tizen/tizen_input_method_context.h | 10 + 6 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 flutter/shell/platform/tizen/tizen_autofill.cc create mode 100644 flutter/shell/platform/tizen/tizen_autofill.h diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 0003094..4049f4a 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -8,6 +8,10 @@ #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" #include "flutter/shell/platform/tizen/logger.h" +#ifdef AUTOFILL_SUPPORT +#include "flutter/shell/platform/tizen/tizen_autofill.h" +#endif + namespace flutter { namespace { @@ -42,6 +46,11 @@ constexpr char kTextKey[] = "text"; constexpr char kBadArgumentError[] = "Bad Arguments"; constexpr char kInternalConsistencyError[] = "Internal Consistency Error"; +constexpr char kRequestAutofillMethod[] = "TextInput.requestAutofill"; +constexpr char kAutofill[] = "autofill"; +constexpr char kUniqueIdentifier[] = "uniqueIdentifier"; +constexpr char kHints[] = "hints"; + bool IsAsciiPrintableKey(char ch) { return ch >= 32 && ch <= 126; } @@ -61,6 +70,10 @@ TextInputChannel::TextInputChannel( std::unique_ptr> result) { HandleMethodCall(call, std::move(result)); }); + TizenAutofill& instance = TizenAutofill::GetInstance(); + instance.SetPopupCallback( + [this]() { input_method_context_->PopupAutofillItems(); }); + instance.SetCommitCallback([this](std::string value) { OnCommit(value); }); } TextInputChannel::~TextInputChannel() {} @@ -222,6 +235,27 @@ void TextInputChannel::HandleMethodCall( } } + auto autofill_iter = client_config.FindMember(kAutofill); + if (autofill_iter != client_config.MemberEnd() && + autofill_iter->value.IsObject()) { + auto unique_identifier_iter = + autofill_iter->value.FindMember(kUniqueIdentifier); + if (unique_identifier_iter != autofill_iter->value.MemberEnd() && + unique_identifier_iter->value.IsString()) { + autofill_id_ = unique_identifier_iter->value.GetString(); + } + + auto hints_iter = autofill_iter->value.FindMember(kHints); + if (hints_iter != autofill_iter->value.MemberEnd() && + hints_iter->value.IsArray()) { + for (auto hint = hints_iter->value.GetArray().Begin(); + hint != hints_iter->value.GetArray().End(); hint++) { + autofill_hints_.clear(); + autofill_hints_.push_back(hint->GetString()); + } + } + } + active_model_ = std::make_unique(); } else if (method.compare(kSetEditingStateMethod) == 0) { input_method_context_->ResetInputMethodContext(); @@ -284,6 +318,11 @@ void TextInputChannel::HandleMethodCall( cursor_offset); } SendStateUpdate(); +#ifdef AUTOFILL_SUPPORT + } else if (method.compare(kRequestAutofillMethod) == 0) { + TizenAutofill& instance = TizenAutofill::GetInstance(); + instance.RequestAutofill(autofill_hints_, autofill_id_); +#endif } else { result->NotImplemented(); return; diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.h b/flutter/shell/platform/tizen/channels/text_input_channel.h index 11d3aa3..25c7ada 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.h +++ b/flutter/shell/platform/tizen/channels/text_input_channel.h @@ -7,6 +7,7 @@ #include #include +#include #include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h" @@ -79,6 +80,10 @@ class TextInputChannel { // Automatic text capitalization type. See available options: // https://api.flutter.dev/flutter/services/TextCapitalization.html std::string text_capitalization_ = ""; + + std::string autofill_id_; + + std::vector autofill_hints_; }; } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_autofill.cc b/flutter/shell/platform/tizen/tizen_autofill.cc new file mode 100644 index 0000000..1c3301a --- /dev/null +++ b/flutter/shell/platform/tizen/tizen_autofill.cc @@ -0,0 +1,187 @@ +// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/tizen/tizen_autofill.h" + +#include +#include + +#include +#include + +#include "flutter/shell/platform/tizen/logger.h" + +TizenAutofill::TizenAutofill() { + InitailizeAutofill(); +} + +TizenAutofill::~TizenAutofill() { + autofill_destroy(ah_); +} + +void TizenAutofill::InitailizeAutofill() { + autofill_create(&ah_); + + int ret; + ret = autofill_connect( + ah_, + [](autofill_h ah, autofill_connection_status_e status, void* user_data) { + }, + NULL); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << __FUNCTION__ << "connect_autofill_daemon error"; + } + + autofill_fill_response_set_received_cb( + ah_, + [](autofill_h ah, autofill_fill_response_h fill_response, void* data) { + int count = 0; + autofill_fill_response_get_group_count(fill_response, &count); + autofill_fill_response_foreach_group( + fill_response, + [](autofill_fill_response_group_h group_h, void* user_data) { + autofill_fill_response_group_foreach_item( + group_h, + [](autofill_fill_response_item_h item, void* user_data) { + char* id = nullptr; + char* value = nullptr; + char* presentation_text = nullptr; + + autofill_fill_response_item_get_id(item, &id); + autofill_fill_response_item_get_presentation_text( + item, &presentation_text); + autofill_fill_response_item_get_value(item, &value); + + std::unique_ptr response_item = + std::make_unique(); + response_item->label_ = std::string(presentation_text); + response_item->id_ = std::string(id); + response_item->value_ = std::string(value); + + TizenAutofill::GetInstance().StoreResponseItem( + move(response_item)); + + if (id) { + free(id); + } + + if (value) { + free(value); + } + + if (presentation_text) { + free(presentation_text); + } + + return true; + }, + group_h); + return true; + }, + &count); + TizenAutofill::GetInstance().CallPopupCallback(); + }, + nullptr); + + response_items_.clear(); +} + +void TizenAutofill::RequestAutofill(std::vector hints, + std::string id) { + char* app_id = nullptr; + app_get_id(&app_id); + + autofill_view_info_h view_info = nullptr; + autofill_view_info_create(&view_info); + autofill_view_info_set_app_id(view_info, app_id); + autofill_view_info_set_view_id(view_info, id.c_str()); + + for (auto hint : hints) { + std::optional autofill_hint = ConvertAutofillHint(hint); + if (autofill_hint.has_value()) { + autofill_item_h item; + autofill_item_create(&item); + autofill_item_set_autofill_hint(item, autofill_hint.value()); + autofill_item_set_id(item, id.c_str()); + autofill_item_set_sensitive_data(item, false); + autofill_view_info_add_item(view_info, item); + autofill_item_destroy(item); + } + } + + int ret = autofill_fill_request(ah_, view_info); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "autofill_fill_request error"; + } + autofill_view_info_destroy(view_info); + + response_items_.clear(); +} + +void TizenAutofill::RegisterAutofillItem(std::string view_id, + AutofillItem item) { + autofill_save_item_h si_h; + + autofill_save_item_create(&si_h); + autofill_save_item_set_autofill_hint(si_h, item.hint_); + autofill_save_item_set_id(si_h, item.id_.c_str()); + autofill_save_item_set_label(si_h, item.label_.c_str()); + autofill_save_item_set_sensitive_data(si_h, item.sensitive_data_); + autofill_save_item_set_value(si_h, item.value_.c_str()); + + char* app_id; + app_get_id(&app_id); + + autofill_save_view_info_h svi_h; + + autofill_save_view_info_create(&svi_h); + autofill_save_view_info_set_app_id(svi_h, app_id); + autofill_save_view_info_set_view_id(svi_h, view_id.c_str()); + + autofill_save_view_info_add_item(svi_h, si_h); + + if (app_id) { + free(app_id); + } + + int ret; + + ret = autofill_commit(ah_, svi_h); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "autofill_commit error"; + } + + autofill_save_view_info_destroy(svi_h); +} + +std::optional TizenAutofill::ConvertAutofillHint( + std::string hint) { + if (hint == "creditCardExpirationDate") { + return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE; + } else if (hint == "creditCardExpirationDay") { + return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY; + } else if (hint == "creditCardExpirationMonth") { + return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH; + } else if (hint == "creditCardExpirationYear") { + return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR; + } else if (hint == "email") { + return AUTOFILL_HINT_EMAIL_ADDRESS; + } else if (hint == "name") { + return AUTOFILL_HINT_NAME; + } else if (hint == "telephoneNumber") { + return AUTOFILL_HINT_PHONE; + } else if (hint == "postalAddress") { + return AUTOFILL_HINT_POSTAL_ADDRESS; + } else if (hint == "postalCode") { + return AUTOFILL_HINT_POSTAL_CODE; + } else if (hint == "username") { + return AUTOFILL_HINT_ID; + } else if (hint == "password") { + return AUTOFILL_HINT_PASSWORD; + } else if (hint == "creditCardSecurityCode") { + return AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE; + } + FT_LOG(Error) << "Not supported autofill hint : " << hint; + return std::nullopt; +} diff --git a/flutter/shell/platform/tizen/tizen_autofill.h b/flutter/shell/platform/tizen/tizen_autofill.h new file mode 100644 index 0000000..a00d7e5 --- /dev/null +++ b/flutter/shell/platform/tizen/tizen_autofill.h @@ -0,0 +1,78 @@ +// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EMBEDDER_TIZEN_AUTOFILL_H_ +#define EMBEDDER_TIZEN_AUTOFILL_H_ + +#include +#include +#include +#include +#include + +#include + +struct AutofillItem { + autofill_hint_e hint_; + bool sensitive_data_; + std::string label_; + std::string id_; + std::string value_; +}; + +class TizenAutofill { + public: + static TizenAutofill& GetInstance() { + static TizenAutofill instance = TizenAutofill(); + return instance; + } + + void RequestAutofill(std::vector hints, std::string id); + + void RegisterAutofillItem(std::string view_id, AutofillItem item); + + void StoreResponseItem(std::unique_ptr item) { + response_items_.push_back(move(item)); + } + + void SetPopupCallback(std::function callback) { + popup_callback_ = callback; + } + + void SetCommitCallback(std::function callback) { + commit_callback_ = callback; + } + + void OnCommit(std::string str) { commit_callback_(str); } + + void CallPopupCallback() { + popup_callback_(); + // response_items_.clear(); + // TODO : reponse_item_ must be cleared when popup is disappeared + } + + const std::vector>& GetAutofillItems() { + return response_items_; + } + + private: + TizenAutofill(); + + ~TizenAutofill(); + + void InitailizeAutofill(); + + // TODO : implement convert flutter hint to tizen hint function + std::optional ConvertAutofillHint(std::string hint); + + autofill_h ah_; + + std::vector> response_items_; + + std::function popup_callback_; + + std::function commit_callback_; +}; + +#endif diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index a4e2a5f..1ff50d4 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -259,6 +259,10 @@ void TizenInputMethodContext::ShowInputPanel() { FT_ASSERT(imf_context_); ecore_imf_context_input_panel_show(imf_context_); ecore_imf_context_focus_in(imf_context_); + int x = 0, y = 0, w = 0, h = 0; + + ecore_imf_context_input_panel_geometry_get(imf_context_, &x, &y, &w, &h); + FT_LOG(Error) << x << " " << y << " " << w << " " << h; } void TizenInputMethodContext::HideInputPanel() { @@ -275,7 +279,6 @@ bool TizenInputMethodContext::IsInputPanelShown() { void TizenInputMethodContext::SetEnableSuggestions(bool enable) { FT_ASSERT(imf_context_); - ecore_imf_context_prediction_allow_set(imf_context_, enable ? EINA_TRUE : EINA_FALSE); } diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index 81abed6..864e641 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -13,12 +13,15 @@ #include #include +#include "flutter/shell/platform/tizen/tizen_autofill.h" + namespace flutter { using OnCommit = std::function; using OnPreeditChanged = std::function; using OnPreeditStart = std::function; using OnPreeditEnd = std::function; +using OnPopupAutofillContext = std::function; struct InputPanelGeometry { int32_t x = 0, y = 0, w = 0, h = 0; @@ -79,6 +82,12 @@ class TizenInputMethodContext { void SetOnPreeditEnd(OnPreeditEnd callback) { on_preedit_end_ = callback; } + void SetOnPopupAutofillContext(OnPopupAutofillContext callback) { + popup_autofill_context_ = callback; + } + + void PopupAutofillItems() { popup_autofill_context_(); } + private: void RegisterEventCallbacks(); void UnregisterEventCallbacks(); @@ -94,6 +103,7 @@ class TizenInputMethodContext { OnPreeditChanged on_preedit_changed_; OnPreeditStart on_preedit_start_; OnPreeditEnd on_preedit_end_; + OnPopupAutofillContext popup_autofill_context_; std::unordered_map event_callbacks_; }; From aa6623bab22ca4a093889bb7bd270227d021640f Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Wed, 1 Feb 2023 18:05:31 +1100 Subject: [PATCH 05/17] Modify BUILD.gn for TizenAutofill --- flutter/shell/platform/tizen/BUILD.gn | 30 ++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index f01d55f..4431572 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -174,7 +174,34 @@ template("embedder") { defines += invoker.defines defines += [ "FLUTTER_ENGINE_NO_PROTOTYPES" ] - if (api_version == "6.5" && target_name != "flutter_tizen_wearable") { + if (api_version == "5.5") { + major_version = 5 + minor_version = 5 + } else if (api_version == "6.0") { + major_version = 6 + minor_version = 0 + } else if (api_version == "6.5") { + major_version = 6 + minor_version = 5 + } else if (api_version == "7.0") { + major_version = 7 + minor_version = 0 + } + + if (major_version >= 6 || (major_version >= 5 && minor_version >= 5)) { + sources += [ + "tizen_autofill.cc", + ] + + libs += [ + "capi-ui-autofill", + "capi-ui-autofill-common", + ] + + defines += [ "AUTOFILL_SUPPORT" ] + } + + if (target_name != "flutter_tizen_wearable" && (major_version >= 7 || (major_version >= 6 && minor_version >= 5))) { sources += [ "flutter_tizen_nui.cc", "tizen_view_nui.cc", @@ -183,6 +210,7 @@ template("embedder") { libs += [ "dali2-adaptor", "dali2-core", + "dali2-toolkit", ] defines += [ "NUI_SUPPORT" ] From 5566608c4f31e848eaf9805ef8e873ce8123ea71 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Wed, 1 Feb 2023 19:07:26 +1100 Subject: [PATCH 06/17] Implement tizen window elementary's ctxpopup_ for autofill --- .../platform/tizen/tizen_window_elementary.cc | 31 +++++++++++++++++++ .../platform/tizen/tizen_window_elementary.h | 3 ++ 2 files changed, 34 insertions(+) diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.cc b/flutter/shell/platform/tizen/tizen_window_elementary.cc index ea993b8..a4d6723 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_window_elementary.cc @@ -8,6 +8,8 @@ #include #include +#include + #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" @@ -426,6 +428,35 @@ void TizenWindowElementary::PrepareInputMethod() { [this]() { view_delegate_->OnComposeEnd(); }); input_method_context_->SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); + +#ifdef AUTOFILL_SUPPORT + ctxpopup_ = elm_ctxpopup_add(elm_win_); + + input_method_context_->SetOnPopupAutofillContext([this]() { + if (TizenAutofill::GetInstance().GetAutofillItems().size() > 0) { + for (auto& item : TizenAutofill::GetInstance().GetAutofillItems()) { + elm_ctxpopup_item_append( + ctxpopup_, item->label_.c_str(), nullptr, + [](void* data, Evas_Object* obj, void* event_info) { + AutofillItem* item = static_cast(data); + TizenAutofill::GetInstance().OnCommit(item->value_); + evas_object_hide(obj); + }, + item.get()); + } + } + // TODO : Change ctxpopup's position to focused input field. + evas_object_move(ctxpopup_, initial_geometry_.left, initial_geometry_.top); + evas_object_show(ctxpopup_); + }); + + evas_object_event_callback_add( + ctxpopup_, EVAS_CALLBACK_HIDE, + [](void* data, Evas* e, Evas_Object* obj, void* event_info) { + elm_ctxpopup_clear(obj); + }, + nullptr); +#endif } int32_t TizenWindowElementary::GetExternalOutputId() { diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.h b/flutter/shell/platform/tizen/tizen_window_elementary.h index ea8aac7..79f17a7 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.h +++ b/flutter/shell/platform/tizen/tizen_window_elementary.h @@ -72,6 +72,9 @@ class TizenWindowElementary : public TizenWindow { Evas_Object* elm_win_ = nullptr; Evas_Object* image_ = nullptr; +#ifdef AUTOFILL_SUPPORT + Evas_Object* ctxpopup_ = nullptr; +#endif Evas_Smart_Cb rotation_changed_callback_ = nullptr; std::unordered_map From 5d3d4b3a791f7324b270249908bd8aee7fa8fb8b Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Wed, 1 Feb 2023 19:12:39 +1100 Subject: [PATCH 07/17] Implement tizen view elementary's ctxpopup_ for autofill --- .../platform/tizen/tizen_view_elementary.cc | 29 +++++++++++++++++++ .../platform/tizen/tizen_view_elementary.h | 3 ++ 2 files changed, 32 insertions(+) diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.cc b/flutter/shell/platform/tizen/tizen_view_elementary.cc index 037d00a..3967fc8 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_view_elementary.cc @@ -8,6 +8,7 @@ #include #include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_autofill.h" #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" namespace flutter { @@ -354,6 +355,34 @@ void TizenViewElementary::PrepareInputMethod() { [this]() { view_delegate_->OnComposeEnd(); }); input_method_context_->SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); +#ifdef AUTOFILL_SUPPORT + ctxpopup_ = elm_ctxpopup_add(container_); + + input_method_context_->SetOnPopupAutofillContext([this]() { + if (TizenAutofill::GetInstance().GetAutofillItems().size() > 0) { + for (auto& item : TizenAutofill::GetInstance().GetAutofillItems()) { + elm_ctxpopup_item_append( + ctxpopup_, item->label_.c_str(), nullptr, + [](void* data, Evas_Object* obj, void* event_info) { + AutofillItem* item = static_cast(data); + TizenAutofill::GetInstance().OnCommit(item->value_); + evas_object_hide(obj); + }, + item.get()); + } + } + // TODO : Change ctxpopup's position to focused input field. + evas_object_move(ctxpopup_, 0, 0); + evas_object_show(ctxpopup_); + }); + + evas_object_event_callback_add( + ctxpopup_, EVAS_CALLBACK_HIDE, + [](void* data, Evas* e, Evas_Object* obj, void* event_info) { + elm_ctxpopup_clear(obj); + }, + nullptr); +#endif } } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.h b/flutter/shell/platform/tizen/tizen_view_elementary.h index 27b8aeb..cdfc700 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.h +++ b/flutter/shell/platform/tizen/tizen_view_elementary.h @@ -51,6 +51,9 @@ class TizenViewElementary : public TizenView { Evas_Object* parent_ = nullptr; Evas_Object* container_ = nullptr; Evas_Object* image_ = nullptr; +#ifdef AUTOFILL_SUPPORT + Evas_Object* ctxpopup_ = nullptr; +#endif std::unordered_map evas_object_callbacks_; From 0f5a10e2328b468e4ba99c81cc6b6be536532aa1 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Wed, 1 Feb 2023 21:29:25 +1100 Subject: [PATCH 08/17] Implement tizen view nui's popup_ for autofill --- flutter/shell/platform/tizen/BUILD.gn | 3 +- .../platform/tizen/nui_autofill_popup.cc | 80 +++++++++++++++++++ .../shell/platform/tizen/nui_autofill_popup.h | 38 +++++++++ .../tizen/tizen_input_method_context.cc | 4 - .../shell/platform/tizen/tizen_view_nui.cc | 7 +- flutter/shell/platform/tizen/tizen_view_nui.h | 2 + 6 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 flutter/shell/platform/tizen/nui_autofill_popup.cc create mode 100644 flutter/shell/platform/tizen/nui_autofill_popup.h diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index 4431572..51ac0c8 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -201,10 +201,11 @@ template("embedder") { defines += [ "AUTOFILL_SUPPORT" ] } - if (target_name != "flutter_tizen_wearable" && (major_version >= 7 || (major_version >= 6 && minor_version >= 5))) { + if ((major_version >= 7 || (major_version >= 6 && minor_version >= 5)) && target_name != "flutter_tizen_wearable") { sources += [ "flutter_tizen_nui.cc", "tizen_view_nui.cc", + "nui_autofill_popup.cc", ] libs += [ diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.cc b/flutter/shell/platform/tizen/nui_autofill_popup.cc new file mode 100644 index 0000000..6e3dc24 --- /dev/null +++ b/flutter/shell/platform/tizen/nui_autofill_popup.cc @@ -0,0 +1,80 @@ +#include "flutter/shell/platform/tizen/nui_autofill_popup.h" + +#include +#include +#include + +#include "flutter/shell/platform/tizen/tizen_autofill.h" + +#include "flutter/shell/platform/tizen/logger.h" + +namespace flutter { +bool NuiAutofillPopup::OnTouch(Dali::Actor actor, + const Dali::TouchEvent& event) { + const Dali::PointState::Type state = event.GetState(0); + if (Dali::PointState::DOWN == state) { + auto t = actor.GetProperty(Dali::Actor::Property::NAME).Get(); + on_commit_(t); + OnHide(); + } + return true; +} + +void NuiAutofillPopup::OnHide() { + // TODO : There is a phenomenon where white traces remain for a while when + // popup disappears. + popup_.SetDisplayState(Dali::Toolkit::Popup::HIDDEN); +} + +void NuiAutofillPopup::OnHidden() { + popup_.Unparent(); + popup_.Reset(); +} + +void NuiAutofillPopup::PrepareAutofill() { + popup_ = Dali::Toolkit::Popup::New(); + popup_.SetProperty(Dali::Actor::Property::NAME, "popup"); + popup_.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, + Dali::ParentOrigin::TOP_LEFT); + popup_.SetProperty(Dali::Actor::Property::ANCHOR_POINT, + Dali::AnchorPoint::TOP_LEFT); + popup_.SetProperty(Dali::Toolkit::Popup::Property::TAIL_VISIBILITY, false); + popup_.SetBackgroundColor(Dali::Color::WHITE_SMOKE); + popup_.OutsideTouchedSignal().Connect(this, &NuiAutofillPopup::OnHide); + popup_.HiddenSignal().Connect(this, &NuiAutofillPopup::OnHidden); + popup_.SetProperty(Dali::Toolkit::Popup::Property::BACKING_ENABLED, false); + popup_.SetProperty(Dali::Toolkit::Popup::Property::AUTO_HIDE_DELAY, 2500); +} + +void NuiAutofillPopup::PopupAutofill(Dali::Actor* actor) { + const auto& items = TizenAutofill::GetInstance().GetAutofillItems(); + if (items.size() > 0) { + PrepareAutofill(); + Dali::Toolkit::TableView content = + Dali::Toolkit::TableView::New(items.size(), 1); + // content.SetCellPadding(Dali::Size(10.0f, 0)); + content.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, + Dali::Dimension::ALL_DIMENSIONS); + content.SetProperty(Dali::Actor::Property::PADDING, + Dali::Vector4(10, 10, 0, 0)); + for (uint32_t i = 0; i < items.size(); ++i) { + auto label = Dali::Toolkit::TextLabel::New(items[i]->label_); + label.SetProperty(Dali::Actor::Property::NAME, items[i]->value_); + label.SetResizePolicy(Dali::ResizePolicy::DIMENSION_DEPENDENCY, + Dali::Dimension::HEIGHT); + label.SetProperty(Dali::Toolkit::TextLabel::Property::TEXT_COLOR, + Dali::Color::WHITE_SMOKE); + label.SetProperty(Dali::Toolkit::TextLabel::Property::POINT_SIZE, 7.0f); + label.TouchedSignal().Connect(this, &NuiAutofillPopup::OnTouch); + content.AddChild(label, Dali::Toolkit::TableView::CellPosition(i, 0)); + content.SetFitHeight(i); + } + popup_.SetProperty(Dali::Actor::Property::SIZE, + Dali::Vector2(140.0f, 35.0f * items.size())); + popup_.SetContent(content); + popup_.SetDisplayState(Dali::Toolkit::Popup::SHOWN); + actor->Add(popup_); + } +} + +} // namespace flutter diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.h b/flutter/shell/platform/tizen/nui_autofill_popup.h new file mode 100644 index 0000000..f1ecf78 --- /dev/null +++ b/flutter/shell/platform/tizen/nui_autofill_popup.h @@ -0,0 +1,38 @@ +// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EMBEDDER_NUI_AUTOFILL_POPUP_H_ +#define EMBEDDER_NUI_AUTOFILL_POPUP_H_ + +#include + +#include + +namespace flutter { + +using OnCommit = std::function; +using OnRendering = std::function; + +class NuiAutofillPopup : public Dali::ConnectionTracker { + public: + bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event); + + void OnHide(); + + void OnHidden(); + + void PrepareAutofill(); + + void PopupAutofill(Dali::Actor* actor); + + void SetOnCommit(OnCommit callback) { on_commit_ = callback; } + + private: + Dali::Toolkit::Popup popup_; + OnCommit on_commit_; +}; + +} // namespace flutter + +#endif diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index 1ff50d4..ff01eaf 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -259,10 +259,6 @@ void TizenInputMethodContext::ShowInputPanel() { FT_ASSERT(imf_context_); ecore_imf_context_input_panel_show(imf_context_); ecore_imf_context_focus_in(imf_context_); - int x = 0, y = 0, w = 0, h = 0; - - ecore_imf_context_input_panel_geometry_get(imf_context_, &x, &y, &w, &h); - FT_LOG(Error) << x << " " << y << " " << w << " " << h; } void TizenInputMethodContext::HideInputPanel() { diff --git a/flutter/shell/platform/tizen/tizen_view_nui.cc b/flutter/shell/platform/tizen/tizen_view_nui.cc index c9eb2eb..017e036 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.cc +++ b/flutter/shell/platform/tizen/tizen_view_nui.cc @@ -5,7 +5,6 @@ #include "flutter/shell/platform/tizen/tizen_view_nui.h" #include - #include #include "flutter/shell/platform/tizen/logger.h" @@ -112,6 +111,12 @@ void TizenViewNui::PrepareInputMethod() { [this]() { view_delegate_->OnComposeEnd(); }); input_method_context_->SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); + + input_method_context_->SetOnPopupAutofillContext( + [this]() { autofill_.PopupAutofill(image_view_); }); + + autofill_.SetOnCommit( + [this](std::string str) { view_delegate_->OnCommit(str); }); } void TizenViewNui::RenderOnce() { diff --git a/flutter/shell/platform/tizen/tizen_view_nui.h b/flutter/shell/platform/tizen/tizen_view_nui.h index 5ddf917..fef63be 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.h +++ b/flutter/shell/platform/tizen/tizen_view_nui.h @@ -12,6 +12,7 @@ #include +#include "flutter/shell/platform/tizen/nui_autofill_popup.h" #include "flutter/shell/platform/tizen/tizen_view.h" namespace flutter { @@ -66,6 +67,7 @@ class TizenViewNui : public TizenView { Dali::NativeImageSourceQueuePtr native_image_queue_; int32_t default_window_id_; std::unique_ptr rendering_callback_; + NuiAutofillPopup autofill_; }; } // namespace flutter From aa1c87dc6e0cdefdf37d7a7c8c1dee4b9ebbb057 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Wed, 8 Feb 2023 19:02:48 +1100 Subject: [PATCH 09/17] Minor clean up Signed-off-by: swan.seo --- flutter/shell/platform/tizen/BUILD.gn | 12 ++++++------ .../tizen/channels/text_input_channel.cc | 9 ++++++--- .../shell/platform/tizen/nui_autofill_popup.cc | 6 ++++-- flutter/shell/platform/tizen/tizen_autofill.cc | 18 +++++++----------- flutter/shell/platform/tizen/tizen_autofill.h | 2 +- .../platform/tizen/tizen_view_elementary.cc | 2 ++ flutter/shell/platform/tizen/tizen_view_nui.cc | 1 + .../platform/tizen/tizen_window_elementary.cc | 3 +++ tools/generate_sysroot.py | 15 +++++++++++---- 9 files changed, 41 insertions(+), 27 deletions(-) diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index 51ac0c8..0026bc7 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -188,10 +188,9 @@ template("embedder") { minor_version = 0 } - if (major_version >= 6 || (major_version >= 5 && minor_version >= 5)) { - sources += [ - "tizen_autofill.cc", - ] + if (((major_version >= 5 && minor_version >= 5) || major_version >= 6) && + target_name != "flutter_tizen_wearable") { + sources += [ "tizen_autofill.cc" ] libs += [ "capi-ui-autofill", @@ -201,11 +200,12 @@ template("embedder") { defines += [ "AUTOFILL_SUPPORT" ] } - if ((major_version >= 7 || (major_version >= 6 && minor_version >= 5)) && target_name != "flutter_tizen_wearable") { + if (((major_version >= 6 && minor_version >= 5) || major_version >= 7) && + target_name != "flutter_tizen_wearable") { sources += [ "flutter_tizen_nui.cc", - "tizen_view_nui.cc", "nui_autofill_popup.cc", + "tizen_view_nui.cc", ] libs += [ diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 4049f4a..b2dcefe 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -27,6 +27,7 @@ constexpr char kMultilineInputType[] = "TextInputType.multiline"; constexpr char kUpdateEditingStateMethod[] = "TextInputClient.updateEditingState"; constexpr char kPerformActionMethod[] = "TextInputClient.performAction"; +constexpr char kRequestAutofillMethod[] = "TextInput.requestAutofill"; constexpr char kSetPlatformViewClient[] = "TextInput.setPlatformViewClient"; constexpr char kTextCapitalization[] = "textCapitalization"; constexpr char kTextEnableSuggestions[] = "enableSuggestions"; @@ -45,8 +46,6 @@ constexpr char kSelectionIsDirectionalKey[] = "selectionIsDirectional"; constexpr char kTextKey[] = "text"; constexpr char kBadArgumentError[] = "Bad Arguments"; constexpr char kInternalConsistencyError[] = "Internal Consistency Error"; - -constexpr char kRequestAutofillMethod[] = "TextInput.requestAutofill"; constexpr char kAutofill[] = "autofill"; constexpr char kUniqueIdentifier[] = "uniqueIdentifier"; constexpr char kHints[] = "hints"; @@ -70,10 +69,12 @@ TextInputChannel::TextInputChannel( std::unique_ptr> result) { HandleMethodCall(call, std::move(result)); }); +#ifdef AUTOFILL_SUPPORT TizenAutofill& instance = TizenAutofill::GetInstance(); instance.SetPopupCallback( [this]() { input_method_context_->PopupAutofillItems(); }); instance.SetCommitCallback([this](std::string value) { OnCommit(value); }); +#endif } TextInputChannel::~TextInputChannel() {} @@ -318,10 +319,12 @@ void TextInputChannel::HandleMethodCall( cursor_offset); } SendStateUpdate(); -#ifdef AUTOFILL_SUPPORT } else if (method.compare(kRequestAutofillMethod) == 0) { +#ifdef AUTOFILL_SUPPORT TizenAutofill& instance = TizenAutofill::GetInstance(); instance.RequestAutofill(autofill_hints_, autofill_id_); +#else + result->NotImplemented(); #endif } else { result->NotImplemented(); diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.cc b/flutter/shell/platform/tizen/nui_autofill_popup.cc index 6e3dc24..22386d3 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.cc +++ b/flutter/shell/platform/tizen/nui_autofill_popup.cc @@ -1,3 +1,7 @@ +// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + #include "flutter/shell/platform/tizen/nui_autofill_popup.h" #include @@ -6,8 +10,6 @@ #include "flutter/shell/platform/tizen/tizen_autofill.h" -#include "flutter/shell/platform/tizen/logger.h" - namespace flutter { bool NuiAutofillPopup::OnTouch(Dali::Actor actor, const Dali::TouchEvent& event) { diff --git a/flutter/shell/platform/tizen/tizen_autofill.cc b/flutter/shell/platform/tizen/tizen_autofill.cc index 1c3301a..3f721b0 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.cc +++ b/flutter/shell/platform/tizen/tizen_autofill.cc @@ -8,7 +8,6 @@ #include #include -#include #include "flutter/shell/platform/tizen/logger.h" @@ -17,15 +16,14 @@ TizenAutofill::TizenAutofill() { } TizenAutofill::~TizenAutofill() { - autofill_destroy(ah_); + autofill_destroy(autofill_); } void TizenAutofill::InitailizeAutofill() { - autofill_create(&ah_); + autofill_create(&autofill_); - int ret; - ret = autofill_connect( - ah_, + int ret = autofill_connect( + autofill_, [](autofill_h ah, autofill_connection_status_e status, void* user_data) { }, NULL); @@ -34,7 +32,7 @@ void TizenAutofill::InitailizeAutofill() { } autofill_fill_response_set_received_cb( - ah_, + autofill_, [](autofill_h ah, autofill_fill_response_h fill_response, void* data) { int count = 0; autofill_fill_response_get_group_count(fill_response, &count); @@ -110,7 +108,7 @@ void TizenAutofill::RequestAutofill(std::vector hints, } } - int ret = autofill_fill_request(ah_, view_info); + int ret = autofill_fill_request(autofill_, view_info); if (ret != AUTOFILL_ERROR_NONE) { FT_LOG(Error) << "autofill_fill_request error"; } @@ -145,9 +143,7 @@ void TizenAutofill::RegisterAutofillItem(std::string view_id, free(app_id); } - int ret; - - ret = autofill_commit(ah_, svi_h); + int ret = autofill_commit(autofill_, svi_h); if (ret != AUTOFILL_ERROR_NONE) { FT_LOG(Error) << "autofill_commit error"; } diff --git a/flutter/shell/platform/tizen/tizen_autofill.h b/flutter/shell/platform/tizen/tizen_autofill.h index a00d7e5..ea96f7c 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.h +++ b/flutter/shell/platform/tizen/tizen_autofill.h @@ -66,7 +66,7 @@ class TizenAutofill { // TODO : implement convert flutter hint to tizen hint function std::optional ConvertAutofillHint(std::string hint); - autofill_h ah_; + autofill_h autofill_; std::vector> response_items_; diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.cc b/flutter/shell/platform/tizen/tizen_view_elementary.cc index 3967fc8..5a878c4 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_view_elementary.cc @@ -8,7 +8,9 @@ #include #include "flutter/shell/platform/tizen/logger.h" +#ifdef AUTOFILL_SUPPORT #include "flutter/shell/platform/tizen/tizen_autofill.h" +#endif #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" namespace flutter { diff --git a/flutter/shell/platform/tizen/tizen_view_nui.cc b/flutter/shell/platform/tizen/tizen_view_nui.cc index 017e036..db06fd9 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.cc +++ b/flutter/shell/platform/tizen/tizen_view_nui.cc @@ -5,6 +5,7 @@ #include "flutter/shell/platform/tizen/tizen_view_nui.h" #include + #include #include "flutter/shell/platform/tizen/logger.h" diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.cc b/flutter/shell/platform/tizen/tizen_window_elementary.cc index a4d6723..4b70f54 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_window_elementary.cc @@ -11,6 +11,9 @@ #include #include "flutter/shell/platform/tizen/logger.h" +#ifdef AUTOFILL_SUPPORT +#include "flutter/shell/platform/tizen/tizen_autofill.h" +#endif #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" namespace flutter { diff --git a/tools/generate_sysroot.py b/tools/generate_sysroot.py index ed12310..81acd4b 100755 --- a/tools/generate_sysroot.py +++ b/tools/generate_sysroot.py @@ -43,10 +43,6 @@ 'capi-system-system-settings-devel', 'capi-ui-efl-util', 'capi-ui-efl-util-devel', - 'capi-ui-autofill', - 'capi-ui-autofill-devel', - 'capi-ui-autofill-common', - 'capi-ui-autofill-common-devel', 'cbhm', 'cbhm-devel', 'coregl', @@ -117,6 +113,14 @@ 'wayland-devel', ] +# Only available for Tizen 5.5 and above. +autofill_packages = [ + 'capi-ui-autofill', + 'capi-ui-autofill-devel', + 'capi-ui-autofill-common', + 'capi-ui-autofill-common-devel', +] + # Only available for Tizen 6.5 and above. dali_packages = [ 'dali2', @@ -159,6 +163,9 @@ def generate_sysroot(sysroot: Path, api_version: float, arch: str, quiet=False): existing_rpms = [f for f in download_path.iterdir() if f.suffix == '.rpm'] packages = base_packages + unified_packages + if api_version >= 5.5: + packages += autofill_packages + if api_version >= 6.5: packages += dali_packages From 6b0a2d87044203a440006c15925611f6183b9247 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Thu, 9 Feb 2023 18:15:02 +1100 Subject: [PATCH 10/17] Delete unnecessary condition of generate_root.py, BUILD.gn --- flutter/shell/platform/tizen/BUILD.gn | 34 +++++---------------------- tools/generate_sysroot.py | 14 ++++------- 2 files changed, 10 insertions(+), 38 deletions(-) diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index 0026bc7..304c57b 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -143,18 +143,23 @@ template("embedder") { "external_texture_pixel_egl.cc", "external_texture_surface_egl.cc", "flutter_platform_node_delegate_tizen.cc", + "tizen_autofill.cc", "tizen_renderer_egl.cc", "tizen_vsync_waiter.cc", "tizen_window_ecore_wl2.cc", ] libs += [ + "capi-ui-autofill", + "capi-ui-autofill-common", "ecore_wl2", "tdm-client", "tizen-extension-client", "EGL", "GLESv2", ] + + defines += [ "AUTOFILL_SUPPORT" ] } if (target_name == "flutter_tizen_common") { @@ -174,34 +179,7 @@ template("embedder") { defines += invoker.defines defines += [ "FLUTTER_ENGINE_NO_PROTOTYPES" ] - if (api_version == "5.5") { - major_version = 5 - minor_version = 5 - } else if (api_version == "6.0") { - major_version = 6 - minor_version = 0 - } else if (api_version == "6.5") { - major_version = 6 - minor_version = 5 - } else if (api_version == "7.0") { - major_version = 7 - minor_version = 0 - } - - if (((major_version >= 5 && minor_version >= 5) || major_version >= 6) && - target_name != "flutter_tizen_wearable") { - sources += [ "tizen_autofill.cc" ] - - libs += [ - "capi-ui-autofill", - "capi-ui-autofill-common", - ] - - defines += [ "AUTOFILL_SUPPORT" ] - } - - if (((major_version >= 6 && minor_version >= 5) || major_version >= 7) && - target_name != "flutter_tizen_wearable") { + if (api_version == "6.5" && target_name != "flutter_tizen_wearable") { sources += [ "flutter_tizen_nui.cc", "nui_autofill_popup.cc", diff --git a/tools/generate_sysroot.py b/tools/generate_sysroot.py index 81acd4b..9b8dbb7 100755 --- a/tools/generate_sysroot.py +++ b/tools/generate_sysroot.py @@ -41,6 +41,10 @@ 'capi-system-info-devel', 'capi-system-system-settings', 'capi-system-system-settings-devel', + 'capi-ui-autofill', + 'capi-ui-autofill-devel', + 'capi-ui-autofill-common', + 'capi-ui-autofill-common-devel', 'capi-ui-efl-util', 'capi-ui-efl-util-devel', 'cbhm', @@ -113,14 +117,6 @@ 'wayland-devel', ] -# Only available for Tizen 5.5 and above. -autofill_packages = [ - 'capi-ui-autofill', - 'capi-ui-autofill-devel', - 'capi-ui-autofill-common', - 'capi-ui-autofill-common-devel', -] - # Only available for Tizen 6.5 and above. dali_packages = [ 'dali2', @@ -163,8 +159,6 @@ def generate_sysroot(sysroot: Path, api_version: float, arch: str, quiet=False): existing_rpms = [f for f in download_path.iterdir() if f.suffix == '.rpm'] packages = base_packages + unified_packages - if api_version >= 5.5: - packages += autofill_packages if api_version >= 6.5: packages += dali_packages From 5821267ff2de7a43ba181cbf1a75c66757637da3 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Thu, 9 Feb 2023 19:13:25 +1100 Subject: [PATCH 11/17] Fix bug when ecore wl2 call autofill --- .../shell/platform/tizen/channels/text_input_channel.h | 2 ++ flutter/shell/platform/tizen/tizen_autofill.h | 6 +----- .../shell/platform/tizen/tizen_input_method_context.h | 10 +++++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.h b/flutter/shell/platform/tizen/channels/text_input_channel.h index 25c7ada..152872e 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.h +++ b/flutter/shell/platform/tizen/channels/text_input_channel.h @@ -83,6 +83,8 @@ class TextInputChannel { std::string autofill_id_; + // Hints for request autofill. See availabel options: + // https://api.flutter.dev/flutter/services/AutofillHints-class.html std::vector autofill_hints_; }; diff --git a/flutter/shell/platform/tizen/tizen_autofill.h b/flutter/shell/platform/tizen/tizen_autofill.h index ea96f7c..4340d1d 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.h +++ b/flutter/shell/platform/tizen/tizen_autofill.h @@ -46,11 +46,7 @@ class TizenAutofill { void OnCommit(std::string str) { commit_callback_(str); } - void CallPopupCallback() { - popup_callback_(); - // response_items_.clear(); - // TODO : reponse_item_ must be cleared when popup is disappeared - } + void CallPopupCallback() { popup_callback_(); } const std::vector>& GetAutofillItems() { return response_items_; diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index 864e641..8fb7ce9 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -83,10 +83,14 @@ class TizenInputMethodContext { void SetOnPreeditEnd(OnPreeditEnd callback) { on_preedit_end_ = callback; } void SetOnPopupAutofillContext(OnPopupAutofillContext callback) { - popup_autofill_context_ = callback; + on_popup_autofill_context_ = callback; } - void PopupAutofillItems() { popup_autofill_context_(); } + void PopupAutofillItems() { + if (on_popup_autofill_context_) { + on_popup_autofill_context_(); + } + } private: void RegisterEventCallbacks(); @@ -103,7 +107,7 @@ class TizenInputMethodContext { OnPreeditChanged on_preedit_changed_; OnPreeditStart on_preedit_start_; OnPreeditEnd on_preedit_end_; - OnPopupAutofillContext popup_autofill_context_; + OnPopupAutofillContext on_popup_autofill_context_; std::unordered_map event_callbacks_; }; From 7978db948f6c1e26800603a2d0b01bfcd6fcbd73 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Thu, 9 Feb 2023 23:13:15 +1100 Subject: [PATCH 12/17] Apply reviewer's comment --- flutter/shell/platform/tizen/BUILD.gn | 2 - .../tizen/channels/text_input_channel.cc | 10 ++-- .../platform/tizen/nui_autofill_popup.cc | 1 - .../shell/platform/tizen/tizen_autofill.cc | 53 ++++++++++--------- flutter/shell/platform/tizen/tizen_autofill.h | 18 +++---- .../platform/tizen/tizen_view_elementary.cc | 27 ++++++---- .../platform/tizen/tizen_view_elementary.h | 3 +- .../platform/tizen/tizen_window_elementary.cc | 31 +++++++---- .../platform/tizen/tizen_window_elementary.h | 3 +- 9 files changed, 82 insertions(+), 66 deletions(-) diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index 304c57b..afe751f 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -158,8 +158,6 @@ template("embedder") { "EGL", "GLESv2", ] - - defines += [ "AUTOFILL_SUPPORT" ] } if (target_name == "flutter_tizen_common") { diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index b2dcefe..84becfc 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -8,7 +8,7 @@ #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" #include "flutter/shell/platform/tizen/logger.h" -#ifdef AUTOFILL_SUPPORT +#ifndef WEARABLE_PROFILE #include "flutter/shell/platform/tizen/tizen_autofill.h" #endif @@ -69,11 +69,11 @@ TextInputChannel::TextInputChannel( std::unique_ptr> result) { HandleMethodCall(call, std::move(result)); }); -#ifdef AUTOFILL_SUPPORT +#ifndef WEARABLE_PROFILE TizenAutofill& instance = TizenAutofill::GetInstance(); - instance.SetPopupCallback( + instance.SetOnPopup( [this]() { input_method_context_->PopupAutofillItems(); }); - instance.SetCommitCallback([this](std::string value) { OnCommit(value); }); + instance.SetOnCommit([this](std::string value) { OnCommit(value); }); #endif } @@ -320,7 +320,7 @@ void TextInputChannel::HandleMethodCall( } SendStateUpdate(); } else if (method.compare(kRequestAutofillMethod) == 0) { -#ifdef AUTOFILL_SUPPORT +#ifndef WEARABLE_PROFILE TizenAutofill& instance = TizenAutofill::GetInstance(); instance.RequestAutofill(autofill_hints_, autofill_id_); #else diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.cc b/flutter/shell/platform/tizen/nui_autofill_popup.cc index 22386d3..4780a6a 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.cc +++ b/flutter/shell/platform/tizen/nui_autofill_popup.cc @@ -54,7 +54,6 @@ void NuiAutofillPopup::PopupAutofill(Dali::Actor* actor) { PrepareAutofill(); Dali::Toolkit::TableView content = Dali::Toolkit::TableView::New(items.size(), 1); - // content.SetCellPadding(Dali::Size(10.0f, 0)); content.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, Dali::Dimension::ALL_DIMENSIONS); content.SetProperty(Dali::Actor::Property::PADDING, diff --git a/flutter/shell/platform/tizen/tizen_autofill.cc b/flutter/shell/platform/tizen/tizen_autofill.cc index 3f721b0..0aee365 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.cc +++ b/flutter/shell/platform/tizen/tizen_autofill.cc @@ -24,23 +24,24 @@ void TizenAutofill::InitailizeAutofill() { int ret = autofill_connect( autofill_, - [](autofill_h ah, autofill_connection_status_e status, void* user_data) { - }, - NULL); + [](autofill_h autofill, autofill_connection_status_e status, + void* user_data) {}, + nullptr); if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << __FUNCTION__ << "connect_autofill_daemon error"; + FT_LOG(Error) << "connect_autofill_daemon error"; } autofill_fill_response_set_received_cb( autofill_, - [](autofill_h ah, autofill_fill_response_h fill_response, void* data) { + [](autofill_h autofill, autofill_fill_response_h fill_response, + void* data) { int count = 0; autofill_fill_response_get_group_count(fill_response, &count); autofill_fill_response_foreach_group( fill_response, - [](autofill_fill_response_group_h group_h, void* user_data) { + [](autofill_fill_response_group_h group, void* user_data) { autofill_fill_response_group_foreach_item( - group_h, + group, [](autofill_fill_response_item_h item, void* user_data) { char* id = nullptr; char* value = nullptr; @@ -74,11 +75,11 @@ void TizenAutofill::InitailizeAutofill() { return true; }, - group_h); + group); return true; }, &count); - TizenAutofill::GetInstance().CallPopupCallback(); + TizenAutofill::GetInstance().OnPopup(); }, nullptr); @@ -95,10 +96,14 @@ void TizenAutofill::RequestAutofill(std::vector hints, autofill_view_info_set_app_id(view_info, app_id); autofill_view_info_set_view_id(view_info, id.c_str()); + if (app_id) { + free(app_id); + } + for (auto hint : hints) { std::optional autofill_hint = ConvertAutofillHint(hint); if (autofill_hint.has_value()) { - autofill_item_h item; + autofill_item_h item = nullptr; autofill_item_create(&item); autofill_item_set_autofill_hint(item, autofill_hint.value()); autofill_item_set_id(item, id.c_str()); @@ -119,36 +124,36 @@ void TizenAutofill::RequestAutofill(std::vector hints, void TizenAutofill::RegisterAutofillItem(std::string view_id, AutofillItem item) { - autofill_save_item_h si_h; + autofill_save_item_h save_item = nullptr; - autofill_save_item_create(&si_h); - autofill_save_item_set_autofill_hint(si_h, item.hint_); - autofill_save_item_set_id(si_h, item.id_.c_str()); - autofill_save_item_set_label(si_h, item.label_.c_str()); - autofill_save_item_set_sensitive_data(si_h, item.sensitive_data_); - autofill_save_item_set_value(si_h, item.value_.c_str()); + autofill_save_item_create(&save_item); + autofill_save_item_set_autofill_hint(save_item, item.hint_); + autofill_save_item_set_id(save_item, item.id_.c_str()); + autofill_save_item_set_label(save_item, item.label_.c_str()); + autofill_save_item_set_sensitive_data(save_item, item.sensitive_data_); + autofill_save_item_set_value(save_item, item.value_.c_str()); char* app_id; app_get_id(&app_id); - autofill_save_view_info_h svi_h; + autofill_save_view_info_h save_view_info = nullptr; - autofill_save_view_info_create(&svi_h); - autofill_save_view_info_set_app_id(svi_h, app_id); - autofill_save_view_info_set_view_id(svi_h, view_id.c_str()); + autofill_save_view_info_create(&save_view_info); + autofill_save_view_info_set_app_id(save_view_info, app_id); + autofill_save_view_info_set_view_id(save_view_info, view_id.c_str()); - autofill_save_view_info_add_item(svi_h, si_h); + autofill_save_view_info_add_item(save_view_info, save_item); if (app_id) { free(app_id); } - int ret = autofill_commit(autofill_, svi_h); + int ret = autofill_commit(autofill_, save_view_info); if (ret != AUTOFILL_ERROR_NONE) { FT_LOG(Error) << "autofill_commit error"; } - autofill_save_view_info_destroy(svi_h); + autofill_save_view_info_destroy(save_view_info); } std::optional TizenAutofill::ConvertAutofillHint( diff --git a/flutter/shell/platform/tizen/tizen_autofill.h b/flutter/shell/platform/tizen/tizen_autofill.h index 4340d1d..2a30d42 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.h +++ b/flutter/shell/platform/tizen/tizen_autofill.h @@ -36,18 +36,16 @@ class TizenAutofill { response_items_.push_back(move(item)); } - void SetPopupCallback(std::function callback) { - popup_callback_ = callback; - } + void SetOnPopup(std::function on_popup) { on_popup_ = on_popup; } - void SetCommitCallback(std::function callback) { - commit_callback_ = callback; + void SetOnCommit(std::function on_commit) { + on_commit_ = on_commit; } - void OnCommit(std::string str) { commit_callback_(str); } - - void CallPopupCallback() { popup_callback_(); } + void OnCommit(std::string str) { on_commit_(str); } + void OnPopup() { on_popup_(); } +# const std::vector>& GetAutofillItems() { return response_items_; } @@ -66,9 +64,9 @@ class TizenAutofill { std::vector> response_items_; - std::function popup_callback_; + std::function on_popup_; - std::function commit_callback_; + std::function on_commit_; }; #endif diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.cc b/flutter/shell/platform/tizen/tizen_view_elementary.cc index 5a878c4..eb9287b 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_view_elementary.cc @@ -8,7 +8,7 @@ #include #include "flutter/shell/platform/tizen/logger.h" -#ifdef AUTOFILL_SUPPORT +#ifndef WEARABLE_PROFILE #include "flutter/shell/platform/tizen/tizen_autofill.h" #endif #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" @@ -97,6 +97,9 @@ bool TizenViewElementary::CreateView() { evas_object_image_size_set(image_, initial_width_, initial_height_); evas_object_image_alpha_set(image_, EINA_TRUE); elm_object_part_content_set(container_, "overlay", image_); +#ifndef WEARABLE_PROFILE + ctxpopup_ = elm_ctxpopup_add(container_); +#endif return true; } @@ -286,6 +289,13 @@ void TizenViewElementary::RegisterEventHandlers() { }; evas_object_smart_callback_add(container_, "focused", focused_callback_, this); + +#ifndef WEARABLE_PROFILE + popup_hide_callback_ = [](void* data, Evas* e, Evas_Object* obj, + void* event_info) { elm_ctxpopup_clear(obj); }; + evas_object_event_callback_add(ctxpopup_, EVAS_CALLBACK_HIDE, + popup_hide_callback_, nullptr); +#endif } void TizenViewElementary::UnregisterEventHandlers() { @@ -309,6 +319,10 @@ void TizenViewElementary::UnregisterEventHandlers() { evas_object_event_callback_del(container_, EVAS_CALLBACK_KEY_UP, evas_object_callbacks_[EVAS_CALLBACK_KEY_UP]); evas_object_smart_callback_del(container_, "focused", focused_callback_); +#ifndef WEARABLE_PROFILE + evas_object_event_callback_del(ctxpopup_, EVAS_CALLBACK_HIDE, + popup_hide_callback_); +#endif } TizenGeometry TizenViewElementary::GetGeometry() { @@ -357,9 +371,7 @@ void TizenViewElementary::PrepareInputMethod() { [this]() { view_delegate_->OnComposeEnd(); }); input_method_context_->SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); -#ifdef AUTOFILL_SUPPORT - ctxpopup_ = elm_ctxpopup_add(container_); - +#ifndef WEARABLE_PROFILE input_method_context_->SetOnPopupAutofillContext([this]() { if (TizenAutofill::GetInstance().GetAutofillItems().size() > 0) { for (auto& item : TizenAutofill::GetInstance().GetAutofillItems()) { @@ -377,13 +389,6 @@ void TizenViewElementary::PrepareInputMethod() { evas_object_move(ctxpopup_, 0, 0); evas_object_show(ctxpopup_); }); - - evas_object_event_callback_add( - ctxpopup_, EVAS_CALLBACK_HIDE, - [](void* data, Evas* e, Evas_Object* obj, void* event_info) { - elm_ctxpopup_clear(obj); - }, - nullptr); #endif } diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.h b/flutter/shell/platform/tizen/tizen_view_elementary.h index cdfc700..ac4ee99 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.h +++ b/flutter/shell/platform/tizen/tizen_view_elementary.h @@ -51,8 +51,9 @@ class TizenViewElementary : public TizenView { Evas_Object* parent_ = nullptr; Evas_Object* container_ = nullptr; Evas_Object* image_ = nullptr; -#ifdef AUTOFILL_SUPPORT +#ifndef WEARABLE_PROFILE Evas_Object* ctxpopup_ = nullptr; + Evas_Object_Event_Cb popup_hide_callback_ = nullptr; #endif std::unordered_map diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.cc b/flutter/shell/platform/tizen/tizen_window_elementary.cc index 4b70f54..e6ed8b9 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_window_elementary.cc @@ -11,7 +11,7 @@ #include #include "flutter/shell/platform/tizen/logger.h" -#ifdef AUTOFILL_SUPPORT +#ifndef WEARABLE_PROFILE #include "flutter/shell/platform/tizen/tizen_autofill.h" #endif #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" @@ -113,6 +113,10 @@ bool TizenWindowElementary::CreateWindow() { initial_geometry_.height); evas_object_raise(elm_win_); +#ifndef WEARABLE_PROFILE + ctxpopup_ = elm_ctxpopup_add(elm_win_); + +#endif image_ = evas_object_image_filled_add(evas_object_evas_get(elm_win_)); evas_object_resize(image_, initial_geometry_.width, initial_geometry_.height); evas_object_move(image_, initial_geometry_.left, initial_geometry_.top); @@ -135,6 +139,9 @@ bool TizenWindowElementary::CreateWindow() { void TizenWindowElementary::DestroyWindow() { evas_object_del(elm_win_); evas_object_del(image_); +#ifndef WEARABLE_PROFILE + evas_object_del(ctxpopup_); +#endif } void TizenWindowElementary::SetWindowOptions() { @@ -326,6 +333,13 @@ void TizenWindowElementary::RegisterEventHandlers() { evas_object_event_callback_add(elm_win_, EVAS_CALLBACK_KEY_UP, evas_object_callbacks_[EVAS_CALLBACK_KEY_UP], this); + +#ifndef WEARABLE_PROFILE + popup_hide_callback_ = [](void* data, Evas* e, Evas_Object* obj, + void* event_info) { elm_ctxpopup_clear(obj); }; + evas_object_event_callback_add(ctxpopup_, EVAS_CALLBACK_HIDE, + popup_hide_callback_, nullptr); +#endif } void TizenWindowElementary::UnregisterEventHandlers() { @@ -350,6 +364,10 @@ void TizenWindowElementary::UnregisterEventHandlers() { evas_object_callbacks_[EVAS_CALLBACK_KEY_DOWN]); evas_object_event_callback_del(elm_win_, EVAS_CALLBACK_KEY_UP, evas_object_callbacks_[EVAS_CALLBACK_KEY_UP]); +#ifndef WEARABLE_PROFILE + evas_object_event_callback_del(ctxpopup_, EVAS_CALLBACK_HIDE, + popup_hide_callback_); +#endif } TizenGeometry TizenWindowElementary::GetGeometry() { @@ -432,9 +450,7 @@ void TizenWindowElementary::PrepareInputMethod() { input_method_context_->SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); -#ifdef AUTOFILL_SUPPORT - ctxpopup_ = elm_ctxpopup_add(elm_win_); - +#ifndef WEARABLE_PROFILE input_method_context_->SetOnPopupAutofillContext([this]() { if (TizenAutofill::GetInstance().GetAutofillItems().size() > 0) { for (auto& item : TizenAutofill::GetInstance().GetAutofillItems()) { @@ -452,13 +468,6 @@ void TizenWindowElementary::PrepareInputMethod() { evas_object_move(ctxpopup_, initial_geometry_.left, initial_geometry_.top); evas_object_show(ctxpopup_); }); - - evas_object_event_callback_add( - ctxpopup_, EVAS_CALLBACK_HIDE, - [](void* data, Evas* e, Evas_Object* obj, void* event_info) { - elm_ctxpopup_clear(obj); - }, - nullptr); #endif } diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.h b/flutter/shell/platform/tizen/tizen_window_elementary.h index 79f17a7..70f6173 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.h +++ b/flutter/shell/platform/tizen/tizen_window_elementary.h @@ -72,8 +72,9 @@ class TizenWindowElementary : public TizenWindow { Evas_Object* elm_win_ = nullptr; Evas_Object* image_ = nullptr; -#ifdef AUTOFILL_SUPPORT +#ifndef WEARABLE_PROFILE Evas_Object* ctxpopup_ = nullptr; + Evas_Object_Event_Cb popup_hide_callback_ = nullptr; #endif Evas_Smart_Cb rotation_changed_callback_ = nullptr; From 9f93270d43cde7b9f905202445886810817e3c0f Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Fri, 10 Feb 2023 17:41:25 +1100 Subject: [PATCH 13/17] Apply reviewer's comments --- .../tizen/channels/text_input_channel.cc | 19 +++++----- .../tizen/channels/text_input_channel.h | 3 +- .../platform/tizen/nui_autofill_popup.cc | 35 ++++++++++++------- .../shell/platform/tizen/nui_autofill_popup.h | 8 +++-- .../shell/platform/tizen/tizen_autofill.cc | 2 +- flutter/shell/platform/tizen/tizen_autofill.h | 3 +- .../platform/tizen/tizen_view_elementary.cc | 14 +++++--- .../platform/tizen/tizen_view_elementary.h | 1 - .../platform/tizen/tizen_window_elementary.cc | 14 +++++--- .../platform/tizen/tizen_window_elementary.h | 1 - 10 files changed, 58 insertions(+), 42 deletions(-) diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 84becfc..92a65d7 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -7,7 +7,6 @@ #include "flutter/shell/platform/common/json_method_codec.h" #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" #include "flutter/shell/platform/tizen/logger.h" - #ifndef WEARABLE_PROFILE #include "flutter/shell/platform/tizen/tizen_autofill.h" #endif @@ -27,7 +26,9 @@ constexpr char kMultilineInputType[] = "TextInputType.multiline"; constexpr char kUpdateEditingStateMethod[] = "TextInputClient.updateEditingState"; constexpr char kPerformActionMethod[] = "TextInputClient.performAction"; +#ifndef WEARABLE_PROFILE constexpr char kRequestAutofillMethod[] = "TextInput.requestAutofill"; +#endif constexpr char kSetPlatformViewClient[] = "TextInput.setPlatformViewClient"; constexpr char kTextCapitalization[] = "textCapitalization"; constexpr char kTextEnableSuggestions[] = "enableSuggestions"; @@ -69,11 +70,12 @@ TextInputChannel::TextInputChannel( std::unique_ptr> result) { HandleMethodCall(call, std::move(result)); }); + #ifndef WEARABLE_PROFILE - TizenAutofill& instance = TizenAutofill::GetInstance(); - instance.SetOnPopup( + TizenAutofill& autofill = TizenAutofill::GetInstance(); + autofill.SetOnPopup( [this]() { input_method_context_->PopupAutofillItems(); }); - instance.SetOnCommit([this](std::string value) { OnCommit(value); }); + autofill.SetOnCommit([this](std::string value) { OnCommit(value); }); #endif } @@ -249,9 +251,9 @@ void TextInputChannel::HandleMethodCall( auto hints_iter = autofill_iter->value.FindMember(kHints); if (hints_iter != autofill_iter->value.MemberEnd() && hints_iter->value.IsArray()) { + autofill_hints_.clear(); for (auto hint = hints_iter->value.GetArray().Begin(); hint != hints_iter->value.GetArray().End(); hint++) { - autofill_hints_.clear(); autofill_hints_.push_back(hint->GetString()); } } @@ -319,12 +321,9 @@ void TextInputChannel::HandleMethodCall( cursor_offset); } SendStateUpdate(); - } else if (method.compare(kRequestAutofillMethod) == 0) { #ifndef WEARABLE_PROFILE - TizenAutofill& instance = TizenAutofill::GetInstance(); - instance.RequestAutofill(autofill_hints_, autofill_id_); -#else - result->NotImplemented(); + } else if (method.compare(kRequestAutofillMethod) == 0) { + TizenAutofill::GetInstance().RequestAutofill(autofill_hints_, autofill_id_); #endif } else { result->NotImplemented(); diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.h b/flutter/shell/platform/tizen/channels/text_input_channel.h index 152872e..769a112 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.h +++ b/flutter/shell/platform/tizen/channels/text_input_channel.h @@ -81,9 +81,10 @@ class TextInputChannel { // https://api.flutter.dev/flutter/services/TextCapitalization.html std::string text_capitalization_ = ""; + // The active autofill client id. std::string autofill_id_; - // Hints for request autofill. See availabel options: + // A list of autofill hint strings. See available options: // https://api.flutter.dev/flutter/services/AutofillHints-class.html std::vector autofill_hints_; }; diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.cc b/flutter/shell/platform/tizen/nui_autofill_popup.cc index 4780a6a..73e8b8d 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.cc +++ b/flutter/shell/platform/tizen/nui_autofill_popup.cc @@ -11,28 +11,34 @@ #include "flutter/shell/platform/tizen/tizen_autofill.h" namespace flutter { -bool NuiAutofillPopup::OnTouch(Dali::Actor actor, + +bool NuiAutofillPopup::Touched(Dali::Actor actor, const Dali::TouchEvent& event) { const Dali::PointState::Type state = event.GetState(0); if (Dali::PointState::DOWN == state) { - auto t = actor.GetProperty(Dali::Actor::Property::NAME).Get(); - on_commit_(t); - OnHide(); + std::string text = + actor.GetProperty(Dali::Actor::Property::NAME).Get(); + on_commit_(text); + Hide(); } return true; } -void NuiAutofillPopup::OnHide() { - // TODO : There is a phenomenon where white traces remain for a while when - // popup disappears. +void NuiAutofillPopup::Hide() { + // TODO(Swanseo0) : There is a phenomenon where white traces remain for a + // while when popup disappears. popup_.SetDisplayState(Dali::Toolkit::Popup::HIDDEN); } -void NuiAutofillPopup::OnHidden() { +void NuiAutofillPopup::Hidden() { popup_.Unparent(); popup_.Reset(); } +void NuiAutofillPopup::OutsideTouched() { + Hide(); +} + void NuiAutofillPopup::PrepareAutofill() { popup_ = Dali::Toolkit::Popup::New(); popup_.SetProperty(Dali::Actor::Property::NAME, "popup"); @@ -42,14 +48,16 @@ void NuiAutofillPopup::PrepareAutofill() { Dali::AnchorPoint::TOP_LEFT); popup_.SetProperty(Dali::Toolkit::Popup::Property::TAIL_VISIBILITY, false); popup_.SetBackgroundColor(Dali::Color::WHITE_SMOKE); - popup_.OutsideTouchedSignal().Connect(this, &NuiAutofillPopup::OnHide); - popup_.HiddenSignal().Connect(this, &NuiAutofillPopup::OnHidden); + popup_.OutsideTouchedSignal().Connect(this, + &NuiAutofillPopup::OutsideTouched); + popup_.HiddenSignal().Connect(this, &NuiAutofillPopup::Hidden); popup_.SetProperty(Dali::Toolkit::Popup::Property::BACKING_ENABLED, false); popup_.SetProperty(Dali::Toolkit::Popup::Property::AUTO_HIDE_DELAY, 2500); } void NuiAutofillPopup::PopupAutofill(Dali::Actor* actor) { - const auto& items = TizenAutofill::GetInstance().GetAutofillItems(); + const std::vector>& items = + TizenAutofill::GetInstance().GetAutofillItems(); if (items.size() > 0) { PrepareAutofill(); Dali::Toolkit::TableView content = @@ -59,14 +67,15 @@ void NuiAutofillPopup::PopupAutofill(Dali::Actor* actor) { content.SetProperty(Dali::Actor::Property::PADDING, Dali::Vector4(10, 10, 0, 0)); for (uint32_t i = 0; i < items.size(); ++i) { - auto label = Dali::Toolkit::TextLabel::New(items[i]->label_); + Dali::Toolkit::TextLabel label = + Dali::Toolkit::TextLabel::New(items[i]->label_); label.SetProperty(Dali::Actor::Property::NAME, items[i]->value_); label.SetResizePolicy(Dali::ResizePolicy::DIMENSION_DEPENDENCY, Dali::Dimension::HEIGHT); label.SetProperty(Dali::Toolkit::TextLabel::Property::TEXT_COLOR, Dali::Color::WHITE_SMOKE); label.SetProperty(Dali::Toolkit::TextLabel::Property::POINT_SIZE, 7.0f); - label.TouchedSignal().Connect(this, &NuiAutofillPopup::OnTouch); + label.TouchedSignal().Connect(this, &NuiAutofillPopup::Touched); content.AddChild(label, Dali::Toolkit::TableView::CellPosition(i, 0)); content.SetFitHeight(i); } diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.h b/flutter/shell/platform/tizen/nui_autofill_popup.h index f1ecf78..78b6d14 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.h +++ b/flutter/shell/platform/tizen/nui_autofill_popup.h @@ -16,11 +16,11 @@ using OnRendering = std::function; class NuiAutofillPopup : public Dali::ConnectionTracker { public: - bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event); + void Hide(); - void OnHide(); + void Hidden(); - void OnHidden(); + void OutsideTouched(); void PrepareAutofill(); @@ -28,6 +28,8 @@ class NuiAutofillPopup : public Dali::ConnectionTracker { void SetOnCommit(OnCommit callback) { on_commit_ = callback; } + bool Touched(Dali::Actor actor, const Dali::TouchEvent& event); + private: Dali::Toolkit::Popup popup_; OnCommit on_commit_; diff --git a/flutter/shell/platform/tizen/tizen_autofill.cc b/flutter/shell/platform/tizen/tizen_autofill.cc index 0aee365..33a6271 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.cc +++ b/flutter/shell/platform/tizen/tizen_autofill.cc @@ -133,7 +133,7 @@ void TizenAutofill::RegisterAutofillItem(std::string view_id, autofill_save_item_set_sensitive_data(save_item, item.sensitive_data_); autofill_save_item_set_value(save_item, item.value_.c_str()); - char* app_id; + char* app_id = nullptr; app_get_id(&app_id); autofill_save_view_info_h save_view_info = nullptr; diff --git a/flutter/shell/platform/tizen/tizen_autofill.h b/flutter/shell/platform/tizen/tizen_autofill.h index 2a30d42..7c1ce02 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.h +++ b/flutter/shell/platform/tizen/tizen_autofill.h @@ -45,7 +45,7 @@ class TizenAutofill { void OnCommit(std::string str) { on_commit_(str); } void OnPopup() { on_popup_(); } -# + const std::vector>& GetAutofillItems() { return response_items_; } @@ -57,7 +57,6 @@ class TizenAutofill { void InitailizeAutofill(); - // TODO : implement convert flutter hint to tizen hint function std::optional ConvertAutofillHint(std::string hint); autofill_h autofill_; diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.cc b/flutter/shell/platform/tizen/tizen_view_elementary.cc index eb9287b..0992984 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_view_elementary.cc @@ -291,10 +291,13 @@ void TizenViewElementary::RegisterEventHandlers() { this); #ifndef WEARABLE_PROFILE - popup_hide_callback_ = [](void* data, Evas* e, Evas_Object* obj, - void* event_info) { elm_ctxpopup_clear(obj); }; + evas_object_callbacks_[EVAS_CALLBACK_HIDE] = + [](void* data, Evas* e, Evas_Object* obj, void* event_info) { + elm_ctxpopup_clear(obj); + }; evas_object_event_callback_add(ctxpopup_, EVAS_CALLBACK_HIDE, - popup_hide_callback_, nullptr); + evas_object_callbacks_[EVAS_CALLBACK_HIDE], + nullptr); #endif } @@ -319,9 +322,10 @@ void TizenViewElementary::UnregisterEventHandlers() { evas_object_event_callback_del(container_, EVAS_CALLBACK_KEY_UP, evas_object_callbacks_[EVAS_CALLBACK_KEY_UP]); evas_object_smart_callback_del(container_, "focused", focused_callback_); + #ifndef WEARABLE_PROFILE evas_object_event_callback_del(ctxpopup_, EVAS_CALLBACK_HIDE, - popup_hide_callback_); + evas_object_callbacks_[EVAS_CALLBACK_HIDE]); #endif } @@ -385,7 +389,7 @@ void TizenViewElementary::PrepareInputMethod() { item.get()); } } - // TODO : Change ctxpopup's position to focused input field. + // TODO(Swanseo0) : Change ctxpopup's position to focused input field. evas_object_move(ctxpopup_, 0, 0); evas_object_show(ctxpopup_); }); diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.h b/flutter/shell/platform/tizen/tizen_view_elementary.h index ac4ee99..dca149d 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.h +++ b/flutter/shell/platform/tizen/tizen_view_elementary.h @@ -53,7 +53,6 @@ class TizenViewElementary : public TizenView { Evas_Object* image_ = nullptr; #ifndef WEARABLE_PROFILE Evas_Object* ctxpopup_ = nullptr; - Evas_Object_Event_Cb popup_hide_callback_ = nullptr; #endif std::unordered_map diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.cc b/flutter/shell/platform/tizen/tizen_window_elementary.cc index e6ed8b9..02676c8 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_window_elementary.cc @@ -335,10 +335,13 @@ void TizenWindowElementary::RegisterEventHandlers() { this); #ifndef WEARABLE_PROFILE - popup_hide_callback_ = [](void* data, Evas* e, Evas_Object* obj, - void* event_info) { elm_ctxpopup_clear(obj); }; + evas_object_callbacks_[EVAS_CALLBACK_HIDE] = + [](void* data, Evas* e, Evas_Object* obj, void* event_info) { + elm_ctxpopup_clear(obj); + }; evas_object_event_callback_add(ctxpopup_, EVAS_CALLBACK_HIDE, - popup_hide_callback_, nullptr); + evas_object_callbacks_[EVAS_CALLBACK_HIDE], + nullptr); #endif } @@ -364,9 +367,10 @@ void TizenWindowElementary::UnregisterEventHandlers() { evas_object_callbacks_[EVAS_CALLBACK_KEY_DOWN]); evas_object_event_callback_del(elm_win_, EVAS_CALLBACK_KEY_UP, evas_object_callbacks_[EVAS_CALLBACK_KEY_UP]); + #ifndef WEARABLE_PROFILE evas_object_event_callback_del(ctxpopup_, EVAS_CALLBACK_HIDE, - popup_hide_callback_); + evas_object_callbacks_[EVAS_CALLBACK_HIDE]); #endif } @@ -464,7 +468,7 @@ void TizenWindowElementary::PrepareInputMethod() { item.get()); } } - // TODO : Change ctxpopup's position to focused input field. + // TODO(Swanseo0) : Change ctxpopup's position to focused input field. evas_object_move(ctxpopup_, initial_geometry_.left, initial_geometry_.top); evas_object_show(ctxpopup_); }); diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.h b/flutter/shell/platform/tizen/tizen_window_elementary.h index 70f6173..78d64f7 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.h +++ b/flutter/shell/platform/tizen/tizen_window_elementary.h @@ -74,7 +74,6 @@ class TizenWindowElementary : public TizenWindow { Evas_Object* image_ = nullptr; #ifndef WEARABLE_PROFILE Evas_Object* ctxpopup_ = nullptr; - Evas_Object_Event_Cb popup_hide_callback_ = nullptr; #endif Evas_Smart_Cb rotation_changed_callback_ = nullptr; From 5aca9c26f968aa9fdeb8ac5977a38ba65b2892b5 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Sat, 11 Feb 2023 01:28:32 +1100 Subject: [PATCH 14/17] Add initailized, connected to TizenAutofill --- .../platform/tizen/nui_autofill_popup.cc | 22 +++--- .../shell/platform/tizen/nui_autofill_popup.h | 21 +++--- .../shell/platform/tizen/tizen_autofill.cc | 68 +++++++++++++------ flutter/shell/platform/tizen/tizen_autofill.h | 18 +++-- .../platform/tizen/tizen_view_elementary.cc | 6 +- .../shell/platform/tizen/tizen_view_nui.cc | 2 +- .../platform/tizen/tizen_window_elementary.cc | 6 +- 7 files changed, 85 insertions(+), 58 deletions(-) diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.cc b/flutter/shell/platform/tizen/nui_autofill_popup.cc index 73e8b8d..708ef00 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.cc +++ b/flutter/shell/platform/tizen/nui_autofill_popup.cc @@ -19,27 +19,23 @@ bool NuiAutofillPopup::Touched(Dali::Actor actor, std::string text = actor.GetProperty(Dali::Actor::Property::NAME).Get(); on_commit_(text); - Hide(); + popup_.SetDisplayState(Dali::Toolkit::Popup::HIDDEN); } return true; } -void NuiAutofillPopup::Hide() { - // TODO(Swanseo0) : There is a phenomenon where white traces remain for a - // while when popup disappears. - popup_.SetDisplayState(Dali::Toolkit::Popup::HIDDEN); -} - void NuiAutofillPopup::Hidden() { + // TODO(Swanseo0): There is a phenomenon where white traces remain for a + // while when popup disappears. popup_.Unparent(); popup_.Reset(); } void NuiAutofillPopup::OutsideTouched() { - Hide(); + popup_.SetDisplayState(Dali::Toolkit::Popup::HIDDEN); } -void NuiAutofillPopup::PrepareAutofill() { +void NuiAutofillPopup::Prepare() { popup_ = Dali::Toolkit::Popup::New(); popup_.SetProperty(Dali::Actor::Property::NAME, "popup"); popup_.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, @@ -55,11 +51,11 @@ void NuiAutofillPopup::PrepareAutofill() { popup_.SetProperty(Dali::Toolkit::Popup::Property::AUTO_HIDE_DELAY, 2500); } -void NuiAutofillPopup::PopupAutofill(Dali::Actor* actor) { +void NuiAutofillPopup::Show(Dali::Actor* actor) { const std::vector>& items = - TizenAutofill::GetInstance().GetAutofillItems(); - if (items.size() > 0) { - PrepareAutofill(); + TizenAutofill::GetInstance().GetResponseItems(); + if (!items.empty()) { + Prepare(); Dali::Toolkit::TableView content = Dali::Toolkit::TableView::New(items.size(), 1); content.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.h b/flutter/shell/platform/tizen/nui_autofill_popup.h index 78b6d14..8df10ce 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.h +++ b/flutter/shell/platform/tizen/nui_autofill_popup.h @@ -11,28 +11,25 @@ namespace flutter { -using OnCommit = std::function; -using OnRendering = std::function; - class NuiAutofillPopup : public Dali::ConnectionTracker { public: - void Hide(); - - void Hidden(); + void Prepare(); - void OutsideTouched(); + void Show(Dali::Actor* actor); - void PrepareAutofill(); + void SetOnCommit(std::function callback) { + on_commit_ = callback; + } - void PopupAutofill(Dali::Actor* actor); + private: + void Hidden(); - void SetOnCommit(OnCommit callback) { on_commit_ = callback; } + void OutsideTouched(); bool Touched(Dali::Actor actor, const Dali::TouchEvent& event); - private: Dali::Toolkit::Popup popup_; - OnCommit on_commit_; + std::function on_commit_; }; } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_autofill.cc b/flutter/shell/platform/tizen/tizen_autofill.cc index 33a6271..484decf 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.cc +++ b/flutter/shell/platform/tizen/tizen_autofill.cc @@ -12,26 +12,35 @@ #include "flutter/shell/platform/tizen/logger.h" TizenAutofill::TizenAutofill() { - InitailizeAutofill(); + Initailize(); } TizenAutofill::~TizenAutofill() { + autofill_fill_response_unset_received_cb(autofill_); autofill_destroy(autofill_); } -void TizenAutofill::InitailizeAutofill() { - autofill_create(&autofill_); +void TizenAutofill::Initailize() { + int ret = AUTOFILL_ERROR_NONE; + if (!autofill_) { + ret = autofill_create(&autofill_); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Fail to create autofill handle."; + return; + } + } - int ret = autofill_connect( + ret = autofill_connect( autofill_, [](autofill_h autofill, autofill_connection_status_e status, - void* user_data) {}, + void* user_data) { TizenAutofill::GetInstance().SetConnected(true); }, nullptr); if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "connect_autofill_daemon error"; + FT_LOG(Error) << "Fail to connect to the autofill daemon."; + return; } - autofill_fill_response_set_received_cb( + ret = autofill_fill_response_set_received_cb( autofill_, [](autofill_h autofill, autofill_fill_response_h fill_response, void* data) { @@ -45,18 +54,18 @@ void TizenAutofill::InitailizeAutofill() { [](autofill_fill_response_item_h item, void* user_data) { char* id = nullptr; char* value = nullptr; - char* presentation_text = nullptr; + char* label = nullptr; autofill_fill_response_item_get_id(item, &id); - autofill_fill_response_item_get_presentation_text( - item, &presentation_text); + autofill_fill_response_item_get_presentation_text(item, + &label); autofill_fill_response_item_get_value(item, &value); std::unique_ptr response_item = std::make_unique(); - response_item->label_ = std::string(presentation_text); response_item->id_ = std::string(id); response_item->value_ = std::string(value); + response_item->label_ = std::string(label); TizenAutofill::GetInstance().StoreResponseItem( move(response_item)); @@ -69,8 +78,8 @@ void TizenAutofill::InitailizeAutofill() { free(value); } - if (presentation_text) { - free(presentation_text); + if (label) { + free(label); } return true; @@ -82,12 +91,26 @@ void TizenAutofill::InitailizeAutofill() { TizenAutofill::GetInstance().OnPopup(); }, nullptr); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Fail to set fill response received callback."; + return; + } response_items_.clear(); + initailzed_ = true; } void TizenAutofill::RequestAutofill(std::vector hints, std::string id) { + if (!initailzed_) { + Initailize(); + return; + } + + if (!connected_) { + return; + } + char* app_id = nullptr; app_get_id(&app_id); @@ -115,17 +138,24 @@ void TizenAutofill::RequestAutofill(std::vector hints, int ret = autofill_fill_request(autofill_, view_info); if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "autofill_fill_request error"; + FT_LOG(Error) << "Fail to request autofill"; } autofill_view_info_destroy(view_info); response_items_.clear(); } -void TizenAutofill::RegisterAutofillItem(std::string view_id, - AutofillItem item) { - autofill_save_item_h save_item = nullptr; +void TizenAutofill::RegisterItem(std::string view_id, AutofillItem item) { + if (!initailzed_) { + Initailize(); + return; + } + + if (!connected_) { + return; + } + autofill_save_item_h save_item = nullptr; autofill_save_item_create(&save_item); autofill_save_item_set_autofill_hint(save_item, item.hint_); autofill_save_item_set_id(save_item, item.id_.c_str()); @@ -137,11 +167,9 @@ void TizenAutofill::RegisterAutofillItem(std::string view_id, app_get_id(&app_id); autofill_save_view_info_h save_view_info = nullptr; - autofill_save_view_info_create(&save_view_info); autofill_save_view_info_set_app_id(save_view_info, app_id); autofill_save_view_info_set_view_id(save_view_info, view_id.c_str()); - autofill_save_view_info_add_item(save_view_info, save_item); if (app_id) { @@ -150,7 +178,7 @@ void TizenAutofill::RegisterAutofillItem(std::string view_id, int ret = autofill_commit(autofill_, save_view_info); if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "autofill_commit error"; + FT_LOG(Error) << "Fail to register autofill item."; } autofill_save_view_info_destroy(save_view_info); diff --git a/flutter/shell/platform/tizen/tizen_autofill.h b/flutter/shell/platform/tizen/tizen_autofill.h index 7c1ce02..56d247a 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.h +++ b/flutter/shell/platform/tizen/tizen_autofill.h @@ -30,15 +30,17 @@ class TizenAutofill { void RequestAutofill(std::vector hints, std::string id); - void RegisterAutofillItem(std::string view_id, AutofillItem item); + void RegisterItem(std::string view_id, AutofillItem item); void StoreResponseItem(std::unique_ptr item) { response_items_.push_back(move(item)); } + void SetConnected(bool connected) { connected_ = connected; }; + void SetOnPopup(std::function on_popup) { on_popup_ = on_popup; } - void SetOnCommit(std::function on_commit) { + void SetOnCommit(std::function on_commit) { on_commit_ = on_commit; } @@ -46,7 +48,7 @@ class TizenAutofill { void OnPopup() { on_popup_(); } - const std::vector>& GetAutofillItems() { + const std::vector>& GetResponseItems() { return response_items_; } @@ -55,17 +57,21 @@ class TizenAutofill { ~TizenAutofill(); - void InitailizeAutofill(); + void Initailize(); std::optional ConvertAutofillHint(std::string hint); - autofill_h autofill_; + bool connected_ = false; + + bool initailzed_ = false; + + autofill_h autofill_ = nullptr; std::vector> response_items_; std::function on_popup_; - std::function on_commit_; + std::function on_commit_; }; #endif diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.cc b/flutter/shell/platform/tizen/tizen_view_elementary.cc index 0992984..c3366fb 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_view_elementary.cc @@ -377,8 +377,8 @@ void TizenViewElementary::PrepareInputMethod() { [this](std::string str) { view_delegate_->OnCommit(str); }); #ifndef WEARABLE_PROFILE input_method_context_->SetOnPopupAutofillContext([this]() { - if (TizenAutofill::GetInstance().GetAutofillItems().size() > 0) { - for (auto& item : TizenAutofill::GetInstance().GetAutofillItems()) { + if (!TizenAutofill::GetInstance().GetResponseItems().empty()) { + for (auto& item : TizenAutofill::GetInstance().GetResponseItems()) { elm_ctxpopup_item_append( ctxpopup_, item->label_.c_str(), nullptr, [](void* data, Evas_Object* obj, void* event_info) { @@ -389,7 +389,7 @@ void TizenViewElementary::PrepareInputMethod() { item.get()); } } - // TODO(Swanseo0) : Change ctxpopup's position to focused input field. + // TODO(Swanseo0): Change ctxpopup's position to focused input field. evas_object_move(ctxpopup_, 0, 0); evas_object_show(ctxpopup_); }); diff --git a/flutter/shell/platform/tizen/tizen_view_nui.cc b/flutter/shell/platform/tizen/tizen_view_nui.cc index db06fd9..a0ff223 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.cc +++ b/flutter/shell/platform/tizen/tizen_view_nui.cc @@ -114,7 +114,7 @@ void TizenViewNui::PrepareInputMethod() { [this](std::string str) { view_delegate_->OnCommit(str); }); input_method_context_->SetOnPopupAutofillContext( - [this]() { autofill_.PopupAutofill(image_view_); }); + [this]() { autofill_.Show(image_view_); }); autofill_.SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.cc b/flutter/shell/platform/tizen/tizen_window_elementary.cc index 02676c8..c2caaa6 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_window_elementary.cc @@ -456,8 +456,8 @@ void TizenWindowElementary::PrepareInputMethod() { #ifndef WEARABLE_PROFILE input_method_context_->SetOnPopupAutofillContext([this]() { - if (TizenAutofill::GetInstance().GetAutofillItems().size() > 0) { - for (auto& item : TizenAutofill::GetInstance().GetAutofillItems()) { + if (!TizenAutofill::GetInstance().GetResponseItems().empty()) { + for (auto& item : TizenAutofill::GetInstance().GetResponseItems()) { elm_ctxpopup_item_append( ctxpopup_, item->label_.c_str(), nullptr, [](void* data, Evas_Object* obj, void* event_info) { @@ -468,7 +468,7 @@ void TizenWindowElementary::PrepareInputMethod() { item.get()); } } - // TODO(Swanseo0) : Change ctxpopup's position to focused input field. + // TODO(Swanseo0): Change ctxpopup's position to focused input field. evas_object_move(ctxpopup_, initial_geometry_.left, initial_geometry_.top); evas_object_show(ctxpopup_); }); From f37e3fd7205ddb979077000fc187865f5a9c6299 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Thu, 16 Feb 2023 01:40:01 +1100 Subject: [PATCH 15/17] Apply reviewer's comment --- .../tizen/channels/text_input_channel.cc | 2 +- .../platform/tizen/nui_autofill_popup.cc | 54 +-- .../shell/platform/tizen/nui_autofill_popup.h | 4 +- .../shell/platform/tizen/tizen_autofill.cc | 345 ++++++++++-------- flutter/shell/platform/tizen/tizen_autofill.h | 23 +- 5 files changed, 244 insertions(+), 184 deletions(-) diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 92a65d7..1b56107 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -323,7 +323,7 @@ void TextInputChannel::HandleMethodCall( SendStateUpdate(); #ifndef WEARABLE_PROFILE } else if (method.compare(kRequestAutofillMethod) == 0) { - TizenAutofill::GetInstance().RequestAutofill(autofill_hints_, autofill_id_); + TizenAutofill::GetInstance().RequestAutofill(autofill_id_, autofill_hints_); #endif } else { result->NotImplemented(); diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.cc b/flutter/shell/platform/tizen/nui_autofill_popup.cc index 708ef00..d723900 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.cc +++ b/flutter/shell/platform/tizen/nui_autofill_popup.cc @@ -54,33 +54,35 @@ void NuiAutofillPopup::Prepare() { void NuiAutofillPopup::Show(Dali::Actor* actor) { const std::vector>& items = TizenAutofill::GetInstance().GetResponseItems(); - if (!items.empty()) { - Prepare(); - Dali::Toolkit::TableView content = - Dali::Toolkit::TableView::New(items.size(), 1); - content.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, - Dali::Dimension::ALL_DIMENSIONS); - content.SetProperty(Dali::Actor::Property::PADDING, - Dali::Vector4(10, 10, 0, 0)); - for (uint32_t i = 0; i < items.size(); ++i) { - Dali::Toolkit::TextLabel label = - Dali::Toolkit::TextLabel::New(items[i]->label_); - label.SetProperty(Dali::Actor::Property::NAME, items[i]->value_); - label.SetResizePolicy(Dali::ResizePolicy::DIMENSION_DEPENDENCY, - Dali::Dimension::HEIGHT); - label.SetProperty(Dali::Toolkit::TextLabel::Property::TEXT_COLOR, - Dali::Color::WHITE_SMOKE); - label.SetProperty(Dali::Toolkit::TextLabel::Property::POINT_SIZE, 7.0f); - label.TouchedSignal().Connect(this, &NuiAutofillPopup::Touched); - content.AddChild(label, Dali::Toolkit::TableView::CellPosition(i, 0)); - content.SetFitHeight(i); - } - popup_.SetProperty(Dali::Actor::Property::SIZE, - Dali::Vector2(140.0f, 35.0f * items.size())); - popup_.SetContent(content); - popup_.SetDisplayState(Dali::Toolkit::Popup::SHOWN); - actor->Add(popup_); + if (items.empty()) { + return; } + + Prepare(); + Dali::Toolkit::TableView content = + Dali::Toolkit::TableView::New(items.size(), 1); + content.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, + Dali::Dimension::ALL_DIMENSIONS); + content.SetProperty(Dali::Actor::Property::PADDING, + Dali::Vector4(10, 10, 0, 0)); + for (uint32_t i = 0; i < items.size(); ++i) { + Dali::Toolkit::TextLabel label = + Dali::Toolkit::TextLabel::New(items[i]->label_); + label.SetProperty(Dali::Actor::Property::NAME, items[i]->value_); + label.SetResizePolicy(Dali::ResizePolicy::DIMENSION_DEPENDENCY, + Dali::Dimension::HEIGHT); + label.SetProperty(Dali::Toolkit::TextLabel::Property::TEXT_COLOR, + Dali::Color::WHITE_SMOKE); + label.SetProperty(Dali::Toolkit::TextLabel::Property::POINT_SIZE, 7.0f); + label.TouchedSignal().Connect(this, &NuiAutofillPopup::Touched); + content.AddChild(label, Dali::Toolkit::TableView::CellPosition(i, 0)); + content.SetFitHeight(i); + } + popup_.SetProperty(Dali::Actor::Property::SIZE, + Dali::Vector2(140.0f, 35.0f * items.size())); + popup_.SetContent(content); + popup_.SetDisplayState(Dali::Toolkit::Popup::SHOWN); + actor->Add(popup_); } } // namespace flutter diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.h b/flutter/shell/platform/tizen/nui_autofill_popup.h index 8df10ce..1295d42 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.h +++ b/flutter/shell/platform/tizen/nui_autofill_popup.h @@ -13,8 +13,6 @@ namespace flutter { class NuiAutofillPopup : public Dali::ConnectionTracker { public: - void Prepare(); - void Show(Dali::Actor* actor); void SetOnCommit(std::function callback) { @@ -22,6 +20,8 @@ class NuiAutofillPopup : public Dali::ConnectionTracker { } private: + void Prepare(); + void Hidden(); void OutsideTouched(); diff --git a/flutter/shell/platform/tizen/tizen_autofill.cc b/flutter/shell/platform/tizen/tizen_autofill.cc index 484decf..b3e27dd 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.cc +++ b/flutter/shell/platform/tizen/tizen_autofill.cc @@ -11,123 +11,139 @@ #include "flutter/shell/platform/tizen/logger.h" -TizenAutofill::TizenAutofill() { - Initailize(); -} +namespace flutter { -TizenAutofill::~TizenAutofill() { - autofill_fill_response_unset_received_cb(autofill_); - autofill_destroy(autofill_); -} +namespace { -void TizenAutofill::Initailize() { - int ret = AUTOFILL_ERROR_NONE; - if (!autofill_) { - ret = autofill_create(&autofill_); - if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "Fail to create autofill handle."; - return; - } +std::optional ConvertAutofillHint(std::string hint) { + if (hint == "creditCardExpirationDate") { + return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE; + } else if (hint == "creditCardExpirationDay") { + return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY; + } else if (hint == "creditCardExpirationMonth") { + return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH; + } else if (hint == "creditCardExpirationYear") { + return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR; + } else if (hint == "email") { + return AUTOFILL_HINT_EMAIL_ADDRESS; + } else if (hint == "name") { + return AUTOFILL_HINT_NAME; + } else if (hint == "telephoneNumber") { + return AUTOFILL_HINT_PHONE; + } else if (hint == "postalAddress") { + return AUTOFILL_HINT_POSTAL_ADDRESS; + } else if (hint == "postalCode") { + return AUTOFILL_HINT_POSTAL_CODE; + } else if (hint == "username") { + return AUTOFILL_HINT_ID; + } else if (hint == "password") { + return AUTOFILL_HINT_PASSWORD; + } else if (hint == "creditCardSecurityCode") { + return AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE; } + FT_LOG(Error) << "Not supported autofill hint : " << hint; + return std::nullopt; +} - ret = autofill_connect( - autofill_, - [](autofill_h autofill, autofill_connection_status_e status, - void* user_data) { TizenAutofill::GetInstance().SetConnected(true); }, - nullptr); - if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "Fail to connect to the autofill daemon."; - return; +bool StoreFillResponseItem(autofill_fill_response_item_h item, void* data) { + char* id = nullptr; + char* value = nullptr; + char* label = nullptr; + + autofill_fill_response_item_get_id(item, &id); + autofill_fill_response_item_get_presentation_text(item, &label); + autofill_fill_response_item_get_value(item, &value); + std::unique_ptr response_item = + std::make_unique(); + response_item->id_ = std::string(id); + response_item->value_ = std::string(value); + response_item->label_ = std::string(label); + + TizenAutofill* tizen_autofill = static_cast(data); + tizen_autofill->StoreResponseItem(move(response_item)); + if (id) { + free(id); } - ret = autofill_fill_response_set_received_cb( - autofill_, - [](autofill_h autofill, autofill_fill_response_h fill_response, - void* data) { - int count = 0; - autofill_fill_response_get_group_count(fill_response, &count); - autofill_fill_response_foreach_group( - fill_response, - [](autofill_fill_response_group_h group, void* user_data) { - autofill_fill_response_group_foreach_item( - group, - [](autofill_fill_response_item_h item, void* user_data) { - char* id = nullptr; - char* value = nullptr; - char* label = nullptr; - - autofill_fill_response_item_get_id(item, &id); - autofill_fill_response_item_get_presentation_text(item, - &label); - autofill_fill_response_item_get_value(item, &value); - - std::unique_ptr response_item = - std::make_unique(); - response_item->id_ = std::string(id); - response_item->value_ = std::string(value); - response_item->label_ = std::string(label); - - TizenAutofill::GetInstance().StoreResponseItem( - move(response_item)); - - if (id) { - free(id); - } - - if (value) { - free(value); - } - - if (label) { - free(label); - } - - return true; - }, - group); - return true; - }, - &count); - TizenAutofill::GetInstance().OnPopup(); - }, - nullptr); - if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "Fail to set fill response received callback."; - return; + if (value) { + free(value); } - response_items_.clear(); - initailzed_ = true; + if (label) { + free(label); + } + return true; } -void TizenAutofill::RequestAutofill(std::vector hints, - std::string id) { - if (!initailzed_) { - Initailize(); - return; +bool StoreForeachItem(autofill_fill_response_group_h group, void* data) { + autofill_fill_response_group_foreach_item(group, StoreFillResponseItem, data); + return true; +}; + +void ResponseReceived(autofill_h autofill, + autofill_fill_response_h fill_response, + void* data) { + autofill_fill_response_foreach_group(fill_response, StoreForeachItem, data); + TizenAutofill* tizen_autofill = static_cast(data); + tizen_autofill->OnPopup(); +}; + +autofill_save_item_h CreateSaveItem(const AutofillItem& item) { + autofill_save_item_h save_item = nullptr; + int ret = autofill_save_item_create(&save_item); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to create autofill save item."; + return nullptr; } - if (!connected_) { - return; + autofill_save_item_set_autofill_hint(save_item, item.hint_); + autofill_save_item_set_id(save_item, item.id_.c_str()); + autofill_save_item_set_label(save_item, item.label_.c_str()); + autofill_save_item_set_sensitive_data(save_item, item.sensitive_data_); + autofill_save_item_set_value(save_item, item.value_.c_str()); + + return save_item; +} + +autofill_save_view_info_h CreateSaveViewInfo(const std::string& view_id, + const AutofillItem& item) { + autofill_save_item_h save_item = CreateSaveItem(item); + if (save_item == nullptr) { + return nullptr; } char* app_id = nullptr; app_get_id(&app_id); - autofill_view_info_h view_info = nullptr; - autofill_view_info_create(&view_info); - autofill_view_info_set_app_id(view_info, app_id); - autofill_view_info_set_view_id(view_info, id.c_str()); + autofill_save_view_info_h save_view_info = nullptr; + int ret = autofill_save_view_info_create(&save_view_info); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to create autofill save view info."; + return nullptr; + } + autofill_save_view_info_set_app_id(save_view_info, app_id); + autofill_save_view_info_set_view_id(save_view_info, view_id.c_str()); + autofill_save_view_info_add_item(save_view_info, save_item); if (app_id) { free(app_id); } + return save_view_info; +} + +void AddItemsToViewInfo(const autofill_view_info_h& view_info, + const std::string id, + const std::vector& hints) { for (auto hint : hints) { std::optional autofill_hint = ConvertAutofillHint(hint); if (autofill_hint.has_value()) { autofill_item_h item = nullptr; - autofill_item_create(&item); + int ret = autofill_item_create(&item); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to create autofill item."; + continue; + } autofill_item_set_autofill_hint(item, autofill_hint.value()); autofill_item_set_id(item, id.c_str()); autofill_item_set_sensitive_data(item, false); @@ -135,82 +151,121 @@ void TizenAutofill::RequestAutofill(std::vector hints, autofill_item_destroy(item); } } +} - int ret = autofill_fill_request(autofill_, view_info); +autofill_view_info_h CreateViewInfo(const std::string& id, + const std::vector& hints) { + char* app_id = nullptr; + app_get_id(&app_id); + + autofill_view_info_h view_info = nullptr; + int ret = autofill_view_info_create(&view_info); if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "Fail to request autofill"; + FT_LOG(Error) << "Failed to create autofill view info."; + return nullptr; } - autofill_view_info_destroy(view_info); + autofill_view_info_set_app_id(view_info, app_id); + autofill_view_info_set_view_id(view_info, id.c_str()); + + if (app_id) { + free(app_id); + } + + AddItemsToViewInfo(view_info, id, hints); + + return view_info; +} + +} // namespace + +TizenAutofill::TizenAutofill() { + Initialize(); +} + +TizenAutofill::~TizenAutofill() { + autofill_fill_response_unset_received_cb(autofill_); + autofill_destroy(autofill_); +} + +void TizenAutofill::Initialize() { + int ret = AUTOFILL_ERROR_NONE; + if (!autofill_) { + ret = autofill_create(&autofill_); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to create autofill handle."; + return; + } + } + + ret = autofill_connect( + autofill_, + [](autofill_h autofill, autofill_connection_status_e status, void* data) { + TizenAutofill* tizen_autofill = static_cast(data); + if (status == AUTOFILL_CONNECTION_STATUS_CONNECTED) { + tizen_autofill->SetConnected(true); + } else { + tizen_autofill->SetConnected(false); + } + }, + this); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to connect to the autofill daemon."; + return; + } + + autofill_fill_response_set_received_cb(autofill_, ResponseReceived, this); response_items_.clear(); + is_initialized_ = true; } -void TizenAutofill::RegisterItem(std::string view_id, AutofillItem item) { - if (!initailzed_) { - Initailize(); +void TizenAutofill::RequestAutofill(const std::string& id, + const std::vector& hints) { + if (!is_initialized_) { + Initialize(); return; } - if (!connected_) { + if (!is_connected_) { return; } - autofill_save_item_h save_item = nullptr; - autofill_save_item_create(&save_item); - autofill_save_item_set_autofill_hint(save_item, item.hint_); - autofill_save_item_set_id(save_item, item.id_.c_str()); - autofill_save_item_set_label(save_item, item.label_.c_str()); - autofill_save_item_set_sensitive_data(save_item, item.sensitive_data_); - autofill_save_item_set_value(save_item, item.value_.c_str()); + autofill_view_info_h view_info = CreateViewInfo(id, hints); + if (view_info == nullptr) { + return; + } - char* app_id = nullptr; - app_get_id(&app_id); + int ret = autofill_fill_request(autofill_, view_info); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to request autofill."; + } + autofill_view_info_destroy(view_info); - autofill_save_view_info_h save_view_info = nullptr; - autofill_save_view_info_create(&save_view_info); - autofill_save_view_info_set_app_id(save_view_info, app_id); - autofill_save_view_info_set_view_id(save_view_info, view_id.c_str()); - autofill_save_view_info_add_item(save_view_info, save_item); + response_items_.clear(); +} - if (app_id) { - free(app_id); +void TizenAutofill::RegisterItem(const std::string& view_id, + const AutofillItem& item) { + if (!is_initialized_) { + Initialize(); + return; + } + + if (!is_connected_) { + return; + } + + autofill_save_view_info_h save_view_info = CreateSaveViewInfo(view_id, item); + if (save_view_info == nullptr) { + return; } int ret = autofill_commit(autofill_, save_view_info); if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "Fail to register autofill item."; + FT_LOG(Error) << "Failed to register autofill item."; } autofill_save_view_info_destroy(save_view_info); } -std::optional TizenAutofill::ConvertAutofillHint( - std::string hint) { - if (hint == "creditCardExpirationDate") { - return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE; - } else if (hint == "creditCardExpirationDay") { - return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY; - } else if (hint == "creditCardExpirationMonth") { - return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH; - } else if (hint == "creditCardExpirationYear") { - return AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR; - } else if (hint == "email") { - return AUTOFILL_HINT_EMAIL_ADDRESS; - } else if (hint == "name") { - return AUTOFILL_HINT_NAME; - } else if (hint == "telephoneNumber") { - return AUTOFILL_HINT_PHONE; - } else if (hint == "postalAddress") { - return AUTOFILL_HINT_POSTAL_ADDRESS; - } else if (hint == "postalCode") { - return AUTOFILL_HINT_POSTAL_CODE; - } else if (hint == "username") { - return AUTOFILL_HINT_ID; - } else if (hint == "password") { - return AUTOFILL_HINT_PASSWORD; - } else if (hint == "creditCardSecurityCode") { - return AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE; - } - FT_LOG(Error) << "Not supported autofill hint : " << hint; - return std::nullopt; -} +} // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_autofill.h b/flutter/shell/platform/tizen/tizen_autofill.h index 56d247a..103ed92 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.h +++ b/flutter/shell/platform/tizen/tizen_autofill.h @@ -13,6 +13,8 @@ #include +namespace flutter { + struct AutofillItem { autofill_hint_e hint_; bool sensitive_data_; @@ -28,15 +30,16 @@ class TizenAutofill { return instance; } - void RequestAutofill(std::vector hints, std::string id); + void RequestAutofill(const std::string& id, + const std::vector& hints); - void RegisterItem(std::string view_id, AutofillItem item); + void RegisterItem(const std::string& view_id, const AutofillItem& item); void StoreResponseItem(std::unique_ptr item) { response_items_.push_back(move(item)); } - void SetConnected(bool connected) { connected_ = connected; }; + void SetConnected(bool connected) { is_connected_ = connected; }; void SetOnPopup(std::function on_popup) { on_popup_ = on_popup; } @@ -44,7 +47,7 @@ class TizenAutofill { on_commit_ = on_commit; } - void OnCommit(std::string str) { on_commit_(str); } + void OnCommit(const std::string& str) { on_commit_(str); } void OnPopup() { on_popup_(); } @@ -57,13 +60,11 @@ class TizenAutofill { ~TizenAutofill(); - void Initailize(); - - std::optional ConvertAutofillHint(std::string hint); + void Initialize(); - bool connected_ = false; + bool is_connected_ = false; - bool initailzed_ = false; + bool is_initialized_ = false; autofill_h autofill_ = nullptr; @@ -74,4 +75,6 @@ class TizenAutofill { std::function on_commit_; }; -#endif +} // namespace flutter + +#endif // EMBEDDER_TIZEN_AUTOFILL_H_ From 9f3b84361cf862c744243af3f5ca43888a325d0f Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Thu, 23 Feb 2023 16:17:54 +1100 Subject: [PATCH 16/17] Apply reviewer's comment. --- .../tizen/channels/text_input_channel.cc | 2 - .../platform/tizen/nui_autofill_popup.cc | 60 ++++++++++--------- .../shell/platform/tizen/nui_autofill_popup.h | 18 ++++-- .../shell/platform/tizen/tizen_autofill.cc | 52 +++++++++------- flutter/shell/platform/tizen/tizen_autofill.h | 18 +++--- .../tizen/tizen_input_method_context.cc | 6 +- .../tizen/tizen_input_method_context.h | 15 +---- .../platform/tizen/tizen_view_elementary.cc | 50 ++++++++++------ .../platform/tizen/tizen_view_elementary.h | 4 ++ .../shell/platform/tizen/tizen_view_nui.cc | 15 +++-- flutter/shell/platform/tizen/tizen_view_nui.h | 2 + .../platform/tizen/tizen_window_elementary.cc | 51 +++++++++------- .../platform/tizen/tizen_window_elementary.h | 4 ++ tools/generate_sysroot.py | 1 - 14 files changed, 170 insertions(+), 128 deletions(-) diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 1b56107..7153b10 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -73,8 +73,6 @@ TextInputChannel::TextInputChannel( #ifndef WEARABLE_PROFILE TizenAutofill& autofill = TizenAutofill::GetInstance(); - autofill.SetOnPopup( - [this]() { input_method_context_->PopupAutofillItems(); }); autofill.SetOnCommit([this](std::string value) { OnCommit(value); }); #endif } diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.cc b/flutter/shell/platform/tizen/nui_autofill_popup.cc index d723900..268be41 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.cc +++ b/flutter/shell/platform/tizen/nui_autofill_popup.cc @@ -5,11 +5,8 @@ #include "flutter/shell/platform/tizen/nui_autofill_popup.h" #include -#include #include -#include "flutter/shell/platform/tizen/tizen_autofill.h" - namespace flutter { bool NuiAutofillPopup::Touched(Dali::Actor actor, @@ -35,7 +32,32 @@ void NuiAutofillPopup::OutsideTouched() { popup_.SetDisplayState(Dali::Toolkit::Popup::HIDDEN); } -void NuiAutofillPopup::Prepare() { +Dali::Toolkit::TableView NuiAutofillPopup::MakeContent( + const std::vector>& items) { + Dali::Toolkit::TableView content = + Dali::Toolkit::TableView::New(items.size(), 1); + content.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, + Dali::Dimension::ALL_DIMENSIONS); + content.SetProperty(Dali::Actor::Property::PADDING, + Dali::Vector4(10, 10, 0, 0)); + for (uint32_t i = 0; i < items.size(); ++i) { + Dali::Toolkit::TextLabel label = + Dali::Toolkit::TextLabel::New(items[i]->label); + label.SetProperty(Dali::Actor::Property::NAME, items[i]->value); + label.SetResizePolicy(Dali::ResizePolicy::DIMENSION_DEPENDENCY, + Dali::Dimension::HEIGHT); + label.SetProperty(Dali::Toolkit::TextLabel::Property::TEXT_COLOR, + Dali::Color::WHITE_SMOKE); + label.SetProperty(Dali::Toolkit::TextLabel::Property::POINT_SIZE, 7.0f); + label.TouchedSignal().Connect(this, &NuiAutofillPopup::Touched); + content.AddChild(label, Dali::Toolkit::TableView::CellPosition(i, 0)); + content.SetFitHeight(i); + } + return content; +} + +void NuiAutofillPopup::Prepare( + const std::vector>& items) { popup_ = Dali::Toolkit::Popup::New(); popup_.SetProperty(Dali::Actor::Property::NAME, "popup"); popup_.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, @@ -49,6 +71,11 @@ void NuiAutofillPopup::Prepare() { popup_.HiddenSignal().Connect(this, &NuiAutofillPopup::Hidden); popup_.SetProperty(Dali::Toolkit::Popup::Property::BACKING_ENABLED, false); popup_.SetProperty(Dali::Toolkit::Popup::Property::AUTO_HIDE_DELAY, 2500); + popup_.SetProperty(Dali::Actor::Property::SIZE, + Dali::Vector2(140.0f, 35.0f * items.size())); + + Dali::Toolkit::TableView content = MakeContent(items); + popup_.SetContent(content); } void NuiAutofillPopup::Show(Dali::Actor* actor) { @@ -58,29 +85,8 @@ void NuiAutofillPopup::Show(Dali::Actor* actor) { return; } - Prepare(); - Dali::Toolkit::TableView content = - Dali::Toolkit::TableView::New(items.size(), 1); - content.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, - Dali::Dimension::ALL_DIMENSIONS); - content.SetProperty(Dali::Actor::Property::PADDING, - Dali::Vector4(10, 10, 0, 0)); - for (uint32_t i = 0; i < items.size(); ++i) { - Dali::Toolkit::TextLabel label = - Dali::Toolkit::TextLabel::New(items[i]->label_); - label.SetProperty(Dali::Actor::Property::NAME, items[i]->value_); - label.SetResizePolicy(Dali::ResizePolicy::DIMENSION_DEPENDENCY, - Dali::Dimension::HEIGHT); - label.SetProperty(Dali::Toolkit::TextLabel::Property::TEXT_COLOR, - Dali::Color::WHITE_SMOKE); - label.SetProperty(Dali::Toolkit::TextLabel::Property::POINT_SIZE, 7.0f); - label.TouchedSignal().Connect(this, &NuiAutofillPopup::Touched); - content.AddChild(label, Dali::Toolkit::TableView::CellPosition(i, 0)); - content.SetFitHeight(i); - } - popup_.SetProperty(Dali::Actor::Property::SIZE, - Dali::Vector2(140.0f, 35.0f * items.size())); - popup_.SetContent(content); + Prepare(items); + popup_.SetDisplayState(Dali::Toolkit::Popup::SHOWN); actor->Add(popup_); } diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.h b/flutter/shell/platform/tizen/nui_autofill_popup.h index 1295d42..37a6531 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.h +++ b/flutter/shell/platform/tizen/nui_autofill_popup.h @@ -6,21 +6,24 @@ #define EMBEDDER_NUI_AUTOFILL_POPUP_H_ #include +#include #include +#include "flutter/shell/platform/tizen/tizen_autofill.h" + +using OnCommit = std::function; + namespace flutter { class NuiAutofillPopup : public Dali::ConnectionTracker { public: void Show(Dali::Actor* actor); - void SetOnCommit(std::function callback) { - on_commit_ = callback; - } + void SetOnCommit(OnCommit callback) { on_commit_ = callback; } private: - void Prepare(); + void Prepare(const std::vector>& items); void Hidden(); @@ -28,10 +31,13 @@ class NuiAutofillPopup : public Dali::ConnectionTracker { bool Touched(Dali::Actor actor, const Dali::TouchEvent& event); + Dali::Toolkit::TableView MakeContent( + const std::vector>& items); + Dali::Toolkit::Popup popup_; - std::function on_commit_; + OnCommit on_commit_; }; } // namespace flutter -#endif +#endif // EMBEDDER_NUI_AUTOFILL_POPUP_H_ diff --git a/flutter/shell/platform/tizen/tizen_autofill.cc b/flutter/shell/platform/tizen/tizen_autofill.cc index b3e27dd..9443e1c 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.cc +++ b/flutter/shell/platform/tizen/tizen_autofill.cc @@ -45,7 +45,8 @@ std::optional ConvertAutofillHint(std::string hint) { return std::nullopt; } -bool StoreFillResponseItem(autofill_fill_response_item_h item, void* data) { +bool StoreFillResponseItem(autofill_fill_response_item_h item, + void* user_data) { char* id = nullptr; char* value = nullptr; char* label = nullptr; @@ -55,12 +56,12 @@ bool StoreFillResponseItem(autofill_fill_response_item_h item, void* data) { autofill_fill_response_item_get_value(item, &value); std::unique_ptr response_item = std::make_unique(); - response_item->id_ = std::string(id); - response_item->value_ = std::string(value); - response_item->label_ = std::string(label); + response_item->id = std::string(id); + response_item->value = std::string(value); + response_item->label = std::string(label); - TizenAutofill* tizen_autofill = static_cast(data); - tizen_autofill->StoreResponseItem(move(response_item)); + TizenAutofill* self = static_cast(user_data); + self->StoreResponseItem(std::move(response_item)); if (id) { free(id); } @@ -75,17 +76,19 @@ bool StoreFillResponseItem(autofill_fill_response_item_h item, void* data) { return true; } -bool StoreForeachItem(autofill_fill_response_group_h group, void* data) { - autofill_fill_response_group_foreach_item(group, StoreFillResponseItem, data); +bool StoreForeachItem(autofill_fill_response_group_h group, void* user_data) { + autofill_fill_response_group_foreach_item(group, StoreFillResponseItem, + user_data); return true; }; void ResponseReceived(autofill_h autofill, autofill_fill_response_h fill_response, - void* data) { - autofill_fill_response_foreach_group(fill_response, StoreForeachItem, data); - TizenAutofill* tizen_autofill = static_cast(data); - tizen_autofill->OnPopup(); + void* user_data) { + autofill_fill_response_foreach_group(fill_response, StoreForeachItem, + user_data); + TizenAutofill* self = static_cast(user_data); + self->OnPopup(); }; autofill_save_item_h CreateSaveItem(const AutofillItem& item) { @@ -96,11 +99,11 @@ autofill_save_item_h CreateSaveItem(const AutofillItem& item) { return nullptr; } - autofill_save_item_set_autofill_hint(save_item, item.hint_); - autofill_save_item_set_id(save_item, item.id_.c_str()); - autofill_save_item_set_label(save_item, item.label_.c_str()); - autofill_save_item_set_sensitive_data(save_item, item.sensitive_data_); - autofill_save_item_set_value(save_item, item.value_.c_str()); + autofill_save_item_set_autofill_hint(save_item, item.hint); + autofill_save_item_set_id(save_item, item.id.c_str()); + autofill_save_item_set_label(save_item, item.label.c_str()); + autofill_save_item_set_sensitive_data(save_item, item.sensitive_data); + autofill_save_item_set_value(save_item, item.value.c_str()); return save_item; } @@ -132,8 +135,8 @@ autofill_save_view_info_h CreateSaveViewInfo(const std::string& view_id, return save_view_info; } -void AddItemsToViewInfo(const autofill_view_info_h& view_info, - const std::string id, +void AddItemsToViewInfo(autofill_view_info_h view_info, + const std::string& id, const std::vector& hints) { for (auto hint : hints) { std::optional autofill_hint = ConvertAutofillHint(hint); @@ -199,17 +202,20 @@ void TizenAutofill::Initialize() { ret = autofill_connect( autofill_, - [](autofill_h autofill, autofill_connection_status_e status, void* data) { - TizenAutofill* tizen_autofill = static_cast(data); + [](autofill_h autofill, autofill_connection_status_e status, + void* user_data) { + TizenAutofill* self = static_cast(user_data); if (status == AUTOFILL_CONNECTION_STATUS_CONNECTED) { - tizen_autofill->SetConnected(true); + self->SetConnected(true); } else { - tizen_autofill->SetConnected(false); + self->SetConnected(false); } }, this); if (ret != AUTOFILL_ERROR_NONE) { FT_LOG(Error) << "Failed to connect to the autofill daemon."; + autofill_destroy(autofill_); + autofill_ = nullptr; return; } diff --git a/flutter/shell/platform/tizen/tizen_autofill.h b/flutter/shell/platform/tizen/tizen_autofill.h index 103ed92..718487a 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.h +++ b/flutter/shell/platform/tizen/tizen_autofill.h @@ -16,11 +16,11 @@ namespace flutter { struct AutofillItem { - autofill_hint_e hint_; - bool sensitive_data_; - std::string label_; - std::string id_; - std::string value_; + autofill_hint_e hint; + bool sensitive_data; + std::string label; + std::string id; + std::string value; }; class TizenAutofill { @@ -36,7 +36,7 @@ class TizenAutofill { void RegisterItem(const std::string& view_id, const AutofillItem& item); void StoreResponseItem(std::unique_ptr item) { - response_items_.push_back(move(item)); + response_items_.push_back(std::move(item)); } void SetConnected(bool connected) { is_connected_ = connected; }; @@ -49,7 +49,11 @@ class TizenAutofill { void OnCommit(const std::string& str) { on_commit_(str); } - void OnPopup() { on_popup_(); } + void OnPopup() { + if (on_popup_) { + on_popup_(); + } + } const std::vector>& GetResponseItems() { return response_items_; diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index ff01eaf..67d63bf 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -284,7 +284,8 @@ void TizenInputMethodContext::SetInputAction(const std::string& input_action) { Ecore_IMF_Input_Panel_Return_Key_Type return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT; - // Not support : none, previous, continueAction, route, emergencycall, newline + // Not supported : none, previous, continueAction, route, emergencyCall, + // newline if (input_action == "TextInputAction.unspecified") { return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT; } else if (input_action == "TextInputAction.done") { @@ -423,15 +424,12 @@ void TizenInputMethodContext::SetContextOptions() { FT_ASSERT(imf_context_); ecore_imf_context_autocapital_type_set(imf_context_, ECORE_IMF_AUTOCAPITAL_TYPE_NONE); - ecore_imf_context_prediction_allow_set(imf_context_, EINA_FALSE); } void TizenInputMethodContext::SetInputPanelOptions() { FT_ASSERT(imf_context_); ecore_imf_context_input_panel_layout_set(imf_context_, ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); - ecore_imf_context_input_panel_return_key_type_set( - imf_context_, ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT); ecore_imf_context_input_panel_language_set( imf_context_, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC); } diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index 8fb7ce9..315dfb1 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -17,8 +17,9 @@ namespace flutter { -using OnCommit = std::function; -using OnPreeditChanged = std::function; +using OnCommit = std::function; +using OnPreeditChanged = + std::function; using OnPreeditStart = std::function; using OnPreeditEnd = std::function; using OnPopupAutofillContext = std::function; @@ -82,16 +83,6 @@ class TizenInputMethodContext { void SetOnPreeditEnd(OnPreeditEnd callback) { on_preedit_end_ = callback; } - void SetOnPopupAutofillContext(OnPopupAutofillContext callback) { - on_popup_autofill_context_ = callback; - } - - void PopupAutofillItems() { - if (on_popup_autofill_context_) { - on_popup_autofill_context_(); - } - } - private: void RegisterEventCallbacks(); void UnregisterEventCallbacks(); diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.cc b/flutter/shell/platform/tizen/tizen_view_elementary.cc index c3366fb..e81f30d 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_view_elementary.cc @@ -55,6 +55,9 @@ TizenViewElementary::TizenViewElementary(int32_t width, } RegisterEventHandlers(); +#ifndef WEARABLE_PROFILE + PrepareAutofill(); +#endif PrepareInputMethod(); Show(); } @@ -97,9 +100,11 @@ bool TizenViewElementary::CreateView() { evas_object_image_size_set(image_, initial_width_, initial_height_); evas_object_image_alpha_set(image_, EINA_TRUE); elm_object_part_content_set(container_, "overlay", image_); + #ifndef WEARABLE_PROFILE ctxpopup_ = elm_ctxpopup_add(container_); #endif + return true; } @@ -360,6 +365,32 @@ void TizenViewElementary::Show() { evas_object_show(image_); } +#ifndef WEARABLE_PROFILE +void TizenViewElementary::PrepareAutofill() { + TizenAutofill& autofill = TizenAutofill::GetInstance(); + autofill.SetOnPopup([this]() { + const std::vector>& items = + TizenAutofill::GetInstance().GetResponseItems(); + if (items.empty()) { + return; + } + for (const auto& item : items) { + elm_ctxpopup_item_append( + ctxpopup_, item->label.c_str(), nullptr, + [](void* data, Evas_Object* obj, void* event_info) { + AutofillItem* item = static_cast(data); + TizenAutofill::GetInstance().OnCommit(item->value); + evas_object_hide(obj); + }, + item.get()); + } + // TODO(Swanseo0): Change ctxpopup's position to focused input field. + evas_object_move(ctxpopup_, 0, 0); + evas_object_show(ctxpopup_); + }); +} +#endif + void TizenViewElementary::PrepareInputMethod() { input_method_context_ = std::make_unique(GetWindowId()); @@ -375,25 +406,6 @@ void TizenViewElementary::PrepareInputMethod() { [this]() { view_delegate_->OnComposeEnd(); }); input_method_context_->SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); -#ifndef WEARABLE_PROFILE - input_method_context_->SetOnPopupAutofillContext([this]() { - if (!TizenAutofill::GetInstance().GetResponseItems().empty()) { - for (auto& item : TizenAutofill::GetInstance().GetResponseItems()) { - elm_ctxpopup_item_append( - ctxpopup_, item->label_.c_str(), nullptr, - [](void* data, Evas_Object* obj, void* event_info) { - AutofillItem* item = static_cast(data); - TizenAutofill::GetInstance().OnCommit(item->value_); - evas_object_hide(obj); - }, - item.get()); - } - } - // TODO(Swanseo0): Change ctxpopup's position to focused input field. - evas_object_move(ctxpopup_, 0, 0); - evas_object_show(ctxpopup_); - }); -#endif } } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.h b/flutter/shell/platform/tizen/tizen_view_elementary.h index dca149d..7a761ab 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.h +++ b/flutter/shell/platform/tizen/tizen_view_elementary.h @@ -46,6 +46,10 @@ class TizenViewElementary : public TizenView { void UnregisterEventHandlers(); +#ifndef WEARABLE_PROFILE + void PrepareAutofill(); +#endif + void PrepareInputMethod(); Evas_Object* parent_ = nullptr; diff --git a/flutter/shell/platform/tizen/tizen_view_nui.cc b/flutter/shell/platform/tizen/tizen_view_nui.cc index a0ff223..65e87cb 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.cc +++ b/flutter/shell/platform/tizen/tizen_view_nui.cc @@ -23,6 +23,7 @@ TizenViewNui::TizenViewNui(int32_t width, native_image_queue_(native_image_queue), default_window_id_(default_window_id) { RegisterEventHandlers(); + PrepareAutofill(); PrepareInputMethod(); Show(); } @@ -97,6 +98,14 @@ void TizenViewNui::OnKey(const char* device_name, } } +void TizenViewNui::PrepareAutofill() { + TizenAutofill& autofill = TizenAutofill::GetInstance(); + autofill.SetOnPopup([this]() { autofill_.Show(image_view_); }); + + autofill_.SetOnCommit( + [this](std::string str) { view_delegate_->OnCommit(str); }); +} + void TizenViewNui::PrepareInputMethod() { input_method_context_ = std::make_unique(GetWindowId()); @@ -112,12 +121,6 @@ void TizenViewNui::PrepareInputMethod() { [this]() { view_delegate_->OnComposeEnd(); }); input_method_context_->SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); - - input_method_context_->SetOnPopupAutofillContext( - [this]() { autofill_.Show(image_view_); }); - - autofill_.SetOnCommit( - [this](std::string str) { view_delegate_->OnCommit(str); }); } void TizenViewNui::RenderOnce() { diff --git a/flutter/shell/platform/tizen/tizen_view_nui.h b/flutter/shell/platform/tizen/tizen_view_nui.h index fef63be..81b73be 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.h +++ b/flutter/shell/platform/tizen/tizen_view_nui.h @@ -59,6 +59,8 @@ class TizenViewNui : public TizenView { void UnregisterEventHandlers(); + void PrepareAutofill(); + void PrepareInputMethod(); void RenderOnce(); diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.cc b/flutter/shell/platform/tizen/tizen_window_elementary.cc index c2caaa6..7f513ee 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_window_elementary.cc @@ -61,6 +61,9 @@ TizenWindowElementary::TizenWindowElementary( SetWindowOptions(); RegisterEventHandlers(); +#ifndef WEARABLE_PROFILE + PrepareAutofill(); +#endif PrepareInputMethod(); Show(); } @@ -115,8 +118,8 @@ bool TizenWindowElementary::CreateWindow() { #ifndef WEARABLE_PROFILE ctxpopup_ = elm_ctxpopup_add(elm_win_); - #endif + image_ = evas_object_image_filled_add(evas_object_evas_get(elm_win_)); evas_object_resize(image_, initial_geometry_.width, initial_geometry_.height); evas_object_move(image_, initial_geometry_.left, initial_geometry_.top); @@ -438,6 +441,32 @@ void TizenWindowElementary::Show() { evas_object_show(elm_win_); } +#ifndef WEARABLE_PROFILE +void TizenWindowElementary::PrepareAutofill() { + TizenAutofill& autofill = TizenAutofill::GetInstance(); + autofill.SetOnPopup([this]() { + const std::vector>& items = + TizenAutofill::GetInstance().GetResponseItems(); + if (items.empty()) { + return; + } + for (const auto& item : items) { + elm_ctxpopup_item_append( + ctxpopup_, item->label.c_str(), nullptr, + [](void* data, Evas_Object* obj, void* event_info) { + AutofillItem* item = static_cast(data); + TizenAutofill::GetInstance().OnCommit(item->value); + evas_object_hide(obj); + }, + item.get()); + } + // TODO(Swanseo0): Change ctxpopup's position to focused input field. + evas_object_move(ctxpopup_, initial_geometry_.left, initial_geometry_.top); + evas_object_show(ctxpopup_); + }); +} +#endif + void TizenWindowElementary::PrepareInputMethod() { input_method_context_ = std::make_unique(GetWindowId()); @@ -453,26 +482,6 @@ void TizenWindowElementary::PrepareInputMethod() { [this]() { view_delegate_->OnComposeEnd(); }); input_method_context_->SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); - -#ifndef WEARABLE_PROFILE - input_method_context_->SetOnPopupAutofillContext([this]() { - if (!TizenAutofill::GetInstance().GetResponseItems().empty()) { - for (auto& item : TizenAutofill::GetInstance().GetResponseItems()) { - elm_ctxpopup_item_append( - ctxpopup_, item->label_.c_str(), nullptr, - [](void* data, Evas_Object* obj, void* event_info) { - AutofillItem* item = static_cast(data); - TizenAutofill::GetInstance().OnCommit(item->value_); - evas_object_hide(obj); - }, - item.get()); - } - } - // TODO(Swanseo0): Change ctxpopup's position to focused input field. - evas_object_move(ctxpopup_, initial_geometry_.left, initial_geometry_.top); - evas_object_show(ctxpopup_); - }); -#endif } int32_t TizenWindowElementary::GetExternalOutputId() { diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.h b/flutter/shell/platform/tizen/tizen_window_elementary.h index 78d64f7..989321c 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.h +++ b/flutter/shell/platform/tizen/tizen_window_elementary.h @@ -68,6 +68,10 @@ class TizenWindowElementary : public TizenWindow { void UnregisterEventHandlers(); +#ifndef WEARABLE_PROFILE + void PrepareAutofill(); +#endif + void PrepareInputMethod(); Evas_Object* elm_win_ = nullptr; diff --git a/tools/generate_sysroot.py b/tools/generate_sysroot.py index 9b8dbb7..67ae2d9 100755 --- a/tools/generate_sysroot.py +++ b/tools/generate_sysroot.py @@ -159,7 +159,6 @@ def generate_sysroot(sysroot: Path, api_version: float, arch: str, quiet=False): existing_rpms = [f for f in download_path.iterdir() if f.suffix == '.rpm'] packages = base_packages + unified_packages - if api_version >= 6.5: packages += dali_packages From 704c6b13baab136ca0a0784cea92ba534efa3022 Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Tue, 21 Mar 2023 18:59:05 +1100 Subject: [PATCH 17/17] Move popup to above input field --- .../tizen/channels/text_input_channel.cc | 26 +++++++++- .../platform/tizen/nui_autofill_popup.cc | 4 +- .../shell/platform/tizen/nui_autofill_popup.h | 2 +- .../shell/platform/tizen/tizen_autofill.cc | 51 +++++++++++++------ .../tizen/tizen_input_method_context.cc | 18 +++---- .../tizen/tizen_input_method_context.h | 12 ++++- .../platform/tizen/tizen_view_elementary.cc | 24 ++++++++- .../shell/platform/tizen/tizen_view_nui.cc | 21 +++++++- .../platform/tizen/tizen_window_elementary.cc | 24 ++++++++- 9 files changed, 146 insertions(+), 36 deletions(-) diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 7153b10..afdf29b 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -29,7 +29,10 @@ constexpr char kPerformActionMethod[] = "TextInputClient.performAction"; #ifndef WEARABLE_PROFILE constexpr char kRequestAutofillMethod[] = "TextInput.requestAutofill"; #endif -constexpr char kSetPlatformViewClient[] = "TextInput.setPlatformViewClient"; +constexpr char kSetPlatformViewClientMethod[] = + "TextInput.setPlatformViewClient"; +constexpr char kSetEditableSizeAndTransformMethod[] = + "TextInput.setEditableSizeAndTransform"; constexpr char kTextCapitalization[] = "textCapitalization"; constexpr char kTextEnableSuggestions[] = "enableSuggestions"; constexpr char kTextInputAction[] = "inputAction"; @@ -45,6 +48,7 @@ constexpr char kSelectionBaseKey[] = "selectionBase"; constexpr char kSelectionExtentKey[] = "selectionExtent"; constexpr char kSelectionIsDirectionalKey[] = "selectionIsDirectional"; constexpr char kTextKey[] = "text"; +constexpr char kTransformKey[] = "transform"; constexpr char kBadArgumentError[] = "Bad Arguments"; constexpr char kInternalConsistencyError[] = "Internal Consistency Error"; constexpr char kAutofill[] = "autofill"; @@ -151,7 +155,7 @@ void TextInputChannel::HandleMethodCall( } else if (method.compare(kHideMethod) == 0) { input_method_context_->HideInputPanel(); input_method_context_->ResetInputMethodContext(); - } else if (method.compare(kSetPlatformViewClient) == 0) { + } else if (method.compare(kSetPlatformViewClientMethod) == 0) { result->NotImplemented(); return; } else if (method.compare(kClearClientMethod) == 0) { @@ -323,6 +327,24 @@ void TextInputChannel::HandleMethodCall( } else if (method.compare(kRequestAutofillMethod) == 0) { TizenAutofill::GetInstance().RequestAutofill(autofill_id_, autofill_hints_); #endif + } else if (method.compare(kSetEditableSizeAndTransformMethod) == 0) { + if (!method_call.arguments() || method_call.arguments()->IsNull()) { + result->Error(kBadArgumentError, "Method invoked without args."); + return; + } + const rapidjson::Document& args = *method_call.arguments(); + auto transform_iter = args.FindMember(kTransformKey); + if (transform_iter != args.MemberEnd() && transform_iter->value.IsArray()) { + // The 12th and 13th values of the array stores x and y values, + // respectively. + auto x_iter = transform_iter->value.GetArray().Begin() + 12; + auto y_iter = transform_iter->value.GetArray().Begin() + 13; + + InputFieldGeometry geometry; + geometry.x = x_iter->GetDouble(); + geometry.y = y_iter->GetDouble(); + input_method_context_->SetInputFieldGeometry(geometry); + } } else { result->NotImplemented(); return; diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.cc b/flutter/shell/platform/tizen/nui_autofill_popup.cc index 268be41..b4e68e2 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.cc +++ b/flutter/shell/platform/tizen/nui_autofill_popup.cc @@ -78,7 +78,7 @@ void NuiAutofillPopup::Prepare( popup_.SetContent(content); } -void NuiAutofillPopup::Show(Dali::Actor* actor) { +void NuiAutofillPopup::Show(Dali::Actor* actor, double_t x, double_t y) { const std::vector>& items = TizenAutofill::GetInstance().GetResponseItems(); if (items.empty()) { @@ -87,6 +87,8 @@ void NuiAutofillPopup::Show(Dali::Actor* actor) { Prepare(items); + popup_.SetProperty(Dali::Actor::Property::POSITION, + Dali::Vector3(x, y, 0.5f)); popup_.SetDisplayState(Dali::Toolkit::Popup::SHOWN); actor->Add(popup_); } diff --git a/flutter/shell/platform/tizen/nui_autofill_popup.h b/flutter/shell/platform/tizen/nui_autofill_popup.h index 37a6531..4e75df7 100644 --- a/flutter/shell/platform/tizen/nui_autofill_popup.h +++ b/flutter/shell/platform/tizen/nui_autofill_popup.h @@ -18,7 +18,7 @@ namespace flutter { class NuiAutofillPopup : public Dali::ConnectionTracker { public: - void Show(Dali::Actor* actor); + void Show(Dali::Actor* actor, double_t x, double_t y); void SetOnCommit(OnCommit callback) { on_commit_ = callback; } diff --git a/flutter/shell/platform/tizen/tizen_autofill.cc b/flutter/shell/platform/tizen/tizen_autofill.cc index 9443e1c..983fdea 100644 --- a/flutter/shell/platform/tizen/tizen_autofill.cc +++ b/flutter/shell/platform/tizen/tizen_autofill.cc @@ -47,13 +47,28 @@ std::optional ConvertAutofillHint(std::string hint) { bool StoreFillResponseItem(autofill_fill_response_item_h item, void* user_data) { + int ret = AUTOFILL_ERROR_NONE; char* id = nullptr; - char* value = nullptr; + ret = autofill_fill_response_item_get_id(item, &id); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to get response item's id."; + return false; + } + char* label = nullptr; + ret = autofill_fill_response_item_get_presentation_text(item, &label); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to get response item's presentation text."; + return false; + } + + char* value = nullptr; + ret = autofill_fill_response_item_get_value(item, &value); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to get response item's value."; + return false; + } - autofill_fill_response_item_get_id(item, &id); - autofill_fill_response_item_get_presentation_text(item, &label); - autofill_fill_response_item_get_value(item, &value); std::unique_ptr response_item = std::make_unique(); response_item->id = std::string(id); @@ -116,10 +131,14 @@ autofill_save_view_info_h CreateSaveViewInfo(const std::string& view_id, } char* app_id = nullptr; - app_get_id(&app_id); + int ret = app_get_id(&app_id); + if (ret != APP_ERROR_NONE) { + FT_LOG(Error) << "Faild to get app id."; + return nullptr; + } autofill_save_view_info_h save_view_info = nullptr; - int ret = autofill_save_view_info_create(&save_view_info); + ret = autofill_save_view_info_create(&save_view_info); if (ret != AUTOFILL_ERROR_NONE) { FT_LOG(Error) << "Failed to create autofill save view info."; return nullptr; @@ -159,10 +178,14 @@ void AddItemsToViewInfo(autofill_view_info_h view_info, autofill_view_info_h CreateViewInfo(const std::string& id, const std::vector& hints) { char* app_id = nullptr; - app_get_id(&app_id); + int ret = app_get_id(&app_id); + if (ret != APP_ERROR_NONE) { + FT_LOG(Error) << "Faild to get app id."; + return nullptr; + } autofill_view_info_h view_info = nullptr; - int ret = autofill_view_info_create(&view_info); + ret = autofill_view_info_create(&view_info); if (ret != AUTOFILL_ERROR_NONE) { FT_LOG(Error) << "Failed to create autofill view info."; return nullptr; @@ -192,12 +215,10 @@ TizenAutofill::~TizenAutofill() { void TizenAutofill::Initialize() { int ret = AUTOFILL_ERROR_NONE; - if (!autofill_) { - ret = autofill_create(&autofill_); - if (ret != AUTOFILL_ERROR_NONE) { - FT_LOG(Error) << "Failed to create autofill handle."; - return; - } + ret = autofill_create(&autofill_); + if (ret != AUTOFILL_ERROR_NONE) { + FT_LOG(Error) << "Failed to create autofill handle."; + return; } ret = autofill_connect( @@ -228,7 +249,6 @@ void TizenAutofill::Initialize() { void TizenAutofill::RequestAutofill(const std::string& id, const std::vector& hints) { if (!is_initialized_) { - Initialize(); return; } @@ -253,7 +273,6 @@ void TizenAutofill::RequestAutofill(const std::string& id, void TizenAutofill::RegisterItem(const std::string& view_id, const AutofillItem& item) { if (!is_initialized_) { - Initialize(); return; } diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index 67d63bf..a0c808e 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -138,7 +138,6 @@ TizenInputMethodContext::TizenInputMethodContext(uintptr_t window_id) { ecore_imf_context_client_window_set(imf_context_, reinterpret_cast(window_id)); - SetContextOptions(); SetInputPanelOptions(); RegisterEventCallbacks(); } @@ -242,6 +241,15 @@ bool TizenInputMethodContext::HandleNuiKeyEvent(const char* device_name, } #endif +void TizenInputMethodContext::SetInputFieldGeometry( + InputFieldGeometry geometry) { + input_field_geometry_ = geometry; +} + +InputFieldGeometry TizenInputMethodContext::GetInputFieldGeometry() { + return input_field_geometry_; +} + InputPanelGeometry TizenInputMethodContext::GetInputPanelGeometry() { FT_ASSERT(imf_context_); InputPanelGeometry geometry; @@ -420,16 +428,8 @@ void TizenInputMethodContext::UnregisterEventCallbacks() { event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_END]); } -void TizenInputMethodContext::SetContextOptions() { - FT_ASSERT(imf_context_); - ecore_imf_context_autocapital_type_set(imf_context_, - ECORE_IMF_AUTOCAPITAL_TYPE_NONE); -} - void TizenInputMethodContext::SetInputPanelOptions() { FT_ASSERT(imf_context_); - ecore_imf_context_input_panel_layout_set(imf_context_, - ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); ecore_imf_context_input_panel_language_set( imf_context_, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC); } diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index 315dfb1..829e3f4 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -28,6 +28,10 @@ struct InputPanelGeometry { int32_t x = 0, y = 0, w = 0, h = 0; }; +struct InputFieldGeometry { + double_t x = 0, y = 0; +}; + class TizenInputMethodContext { public: TizenInputMethodContext(uintptr_t window_id); @@ -51,6 +55,10 @@ class TizenInputMethodContext { bool is_down); #endif + void SetInputFieldGeometry(InputFieldGeometry); + + InputFieldGeometry GetInputFieldGeometry(); + InputPanelGeometry GetInputPanelGeometry(); void ResetInputMethodContext(); @@ -87,7 +95,6 @@ class TizenInputMethodContext { void RegisterEventCallbacks(); void UnregisterEventCallbacks(); - void SetContextOptions(); void SetInputPanelOptions(); #ifdef NUI_SUPPORT @@ -98,9 +105,10 @@ class TizenInputMethodContext { OnPreeditChanged on_preedit_changed_; OnPreeditStart on_preedit_start_; OnPreeditEnd on_preedit_end_; - OnPopupAutofillContext on_popup_autofill_context_; std::unordered_map event_callbacks_; + + InputFieldGeometry input_field_geometry_; }; } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_view_elementary.cc b/flutter/shell/platform/tizen/tizen_view_elementary.cc index e81f30d..de5aade 100644 --- a/flutter/shell/platform/tizen/tizen_view_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_view_elementary.cc @@ -13,6 +13,14 @@ #endif #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" +#if defined(MOBILE_PROFILE) +constexpr double kProfileFactor = 0.7; +#elif defined(TV_PROFILE) +constexpr double kProfileFactor = 2.0; +#elif not defined(WEARABLE_PROFILE) +constexpr double kProfileFactor = 1.0; +#endif + namespace flutter { namespace { @@ -103,6 +111,9 @@ bool TizenViewElementary::CreateView() { #ifndef WEARABLE_PROFILE ctxpopup_ = elm_ctxpopup_add(container_); + elm_ctxpopup_direction_priority_set( + ctxpopup_, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_RIGHT, + ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_UP); #endif return true; @@ -384,8 +395,17 @@ void TizenViewElementary::PrepareAutofill() { }, item.get()); } - // TODO(Swanseo0): Change ctxpopup's position to focused input field. - evas_object_move(ctxpopup_, 0, 0); +// TODO(Swanseo0): Change ctxpopup's position to focused input field. +#ifdef TV_PROFILE + double_t dpi = 72.0; +#else + double_t dpi = static_cast(GetDpi()); +#endif + double_t scale_factor = dpi / 90.0 * kProfileFactor; + InputFieldGeometry geometry = + input_method_context_->GetInputFieldGeometry(); + evas_object_move(ctxpopup_, geometry.x * scale_factor, + geometry.y * scale_factor); evas_object_show(ctxpopup_); }); } diff --git a/flutter/shell/platform/tizen/tizen_view_nui.cc b/flutter/shell/platform/tizen/tizen_view_nui.cc index 65e87cb..5215f48 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.cc +++ b/flutter/shell/platform/tizen/tizen_view_nui.cc @@ -11,6 +11,14 @@ #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" +#if defined(MOBILE_PROFILE) +constexpr double kProfileFactor = 0.7; +#elif defined(TV_PROFILE) +constexpr double kProfileFactor = 2.0; +#elif not defined(WEARABLE_PROFILE) +constexpr double kProfileFactor = 1.0; +#endif + namespace flutter { TizenViewNui::TizenViewNui(int32_t width, @@ -100,7 +108,18 @@ void TizenViewNui::OnKey(const char* device_name, void TizenViewNui::PrepareAutofill() { TizenAutofill& autofill = TizenAutofill::GetInstance(); - autofill.SetOnPopup([this]() { autofill_.Show(image_view_); }); + autofill.SetOnPopup([this]() { +#ifdef TV_PROFILE + double_t dpi = 72.0; +#else + double_t dpi = static_cast(GetDpi()); +#endif + double_t scale_factor = dpi / 90.0 * kProfileFactor; + InputFieldGeometry geometry = + input_method_context_->GetInputFieldGeometry(); + autofill_.Show(image_view_, geometry.x * scale_factor, + geometry.y * scale_factor); + }); autofill_.SetOnCommit( [this](std::string str) { view_delegate_->OnCommit(str); }); diff --git a/flutter/shell/platform/tizen/tizen_window_elementary.cc b/flutter/shell/platform/tizen/tizen_window_elementary.cc index 7f513ee..0615ce5 100644 --- a/flutter/shell/platform/tizen/tizen_window_elementary.cc +++ b/flutter/shell/platform/tizen/tizen_window_elementary.cc @@ -16,6 +16,14 @@ #endif #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" +#if defined(MOBILE_PROFILE) +constexpr double kProfileFactor = 0.7; +#elif defined(TV_PROFILE) +constexpr double kProfileFactor = 2.0; +#elif not defined(WEARABLE_PROFILE) +constexpr double kProfileFactor = 1.0; +#endif + namespace flutter { namespace { @@ -118,6 +126,9 @@ bool TizenWindowElementary::CreateWindow() { #ifndef WEARABLE_PROFILE ctxpopup_ = elm_ctxpopup_add(elm_win_); + elm_ctxpopup_direction_priority_set( + ctxpopup_, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_RIGHT, + ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_UP); #endif image_ = evas_object_image_filled_add(evas_object_evas_get(elm_win_)); @@ -460,8 +471,17 @@ void TizenWindowElementary::PrepareAutofill() { }, item.get()); } - // TODO(Swanseo0): Change ctxpopup's position to focused input field. - evas_object_move(ctxpopup_, initial_geometry_.left, initial_geometry_.top); +// TODO(Swanseo0): Change ctxpopup's position to focused input field. +#ifdef TV_PROFILE + double_t dpi = 72.0; +#else + double_t dpi = static_cast(GetDpi()); +#endif + double_t scale_factor = dpi / 90.0 * kProfileFactor; + InputFieldGeometry geometry = + input_method_context_->GetInputFieldGeometry(); + evas_object_move(ctxpopup_, geometry.x * scale_factor, + geometry.y * scale_factor); evas_object_show(ctxpopup_); }); }