diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn index e207aba0a93f5..44ecd83653f7a 100644 --- a/shell/platform/tizen/BUILD.gn +++ b/shell/platform/tizen/BUILD.gn @@ -211,6 +211,7 @@ template("embedder") { "//flutter/shell/platform/common:common_cpp_input", "//flutter/shell/platform/common:common_cpp_library_headers", "//flutter/shell/platform/common/client_wrapper:client_wrapper", + "//third_party/dart/runtime:dart_api", "//third_party/rapidjson", ] } diff --git a/shell/platform/tizen/channels/app_control.cc b/shell/platform/tizen/channels/app_control.cc index becd351f05f90..4d08f9e2b1eef 100644 --- a/shell/platform/tizen/channels/app_control.cc +++ b/shell/platform/tizen/channels/app_control.cc @@ -5,17 +5,69 @@ #include "app_control.h" #include "flutter/shell/platform/tizen/channels/app_control_channel.h" +#include "flutter/shell/platform/tizen/logger.h" + +intptr_t NativeInitializeDartApi(void* data) { + return Dart_InitializeApiDL(data); +} + +int32_t NativeCreateAppControl(Dart_Handle handle) { + auto app_control = std::make_unique(); + if (!app_control->handle()) { + return -1; + } + auto id = app_control->id(); + Dart_NewFinalizableHandle_DL( + handle, app_control.get(), 64, + [](void* isolate_callback_data, void* peer) { + auto app_control = reinterpret_cast(peer); + flutter::AppControlManager::GetInstance().Remove(app_control->id()); + }); + flutter::AppControlManager::GetInstance().Insert(std::move(app_control)); + return id; +} + +bool NativeAttachAppControl(int32_t id, Dart_Handle handle) { + auto app_control = flutter::AppControlManager::GetInstance().FindById(id); + if (!app_control || !app_control->handle()) { + return false; + } + Dart_NewFinalizableHandle_DL( + handle, app_control, 64, [](void* isolate_callback_data, void* peer) { + auto app_control = reinterpret_cast(peer); + flutter::AppControlManager::GetInstance().Remove(app_control->id()); + }); + return true; +} namespace flutter { -int AppControl::next_id_ = 0; +int32_t AppControl::next_id_ = 0; -AppControl::AppControl(app_control_h app_control) : id_(next_id_++) { - handle_ = app_control; +AppControl::AppControl() : id_(next_id_++) { + app_control_h handle = nullptr; + AppControlResult ret = app_control_create(&handle); + if (!ret) { + FT_LOG(Error) << "app_control_create() failed: " << ret.message(); + return; + } + handle_ = handle; +} + +AppControl::AppControl(app_control_h handle) : id_(next_id_++) { + app_control_h clone = nullptr; + AppControlResult ret = app_control_clone(&clone, handle); + if (!ret) { + FT_LOG(Error) << "app_control_clone() failed: " << ret.message(); + return; + } + handle_ = clone; } AppControl::~AppControl() { - app_control_destroy(handle_); + if (handle_) { + app_control_destroy(handle_); + } } AppControlResult AppControl::GetString(std::string& str, @@ -109,14 +161,6 @@ AppControlResult AppControl::SetExtraData(const EncodableMap& map) { return AppControlResult(); } -void AppControl::SetManager(AppControlChannel* manager) { - manager_ = manager; -} - -AppControlChannel* AppControl::GetManager() { - return manager_; -} - AppControlResult AppControl::GetOperation(std::string& operation) { return GetString(operation, app_control_get_operation); } @@ -183,6 +227,12 @@ AppControlResult AppControl::SetLaunchMode(const std::string& launch_mode) { return AppControlResult(ret); } +bool AppControl::IsReplyRequested() { + bool requested = false; + app_control_is_reply_requested(handle_, &requested); + return requested; +} + EncodableValue AppControl::SerializeAppControlToMap() { std::string app_id, operation, mime, category, uri, caller_id, launch_mode; AppControlResult results[7]; @@ -202,43 +252,31 @@ EncodableValue AppControl::SerializeAppControlToMap() { } } EncodableMap map; - map[EncodableValue("id")] = EncodableValue(GetId()); + map[EncodableValue("id")] = EncodableValue(id()); map[EncodableValue("appId")] = EncodableValue(app_id); map[EncodableValue("operation")] = EncodableValue(operation); map[EncodableValue("mime")] = EncodableValue(mime); map[EncodableValue("category")] = EncodableValue(category); map[EncodableValue("uri")] = EncodableValue(uri); - map[EncodableValue("callerId")] = EncodableValue(caller_id); + map[EncodableValue("callerAppId")] = EncodableValue(caller_id); map[EncodableValue("launchMode")] = EncodableValue(launch_mode); map[EncodableValue("extraData")] = EncodableValue(extra_data); + map[EncodableValue("shouldReply")] = EncodableValue(IsReplyRequested()); return EncodableValue(map); } AppControlResult AppControl::SendLaunchRequest() { - AppControlResult ret = - app_control_send_launch_request(handle_, nullptr, nullptr); - return ret; + return app_control_send_launch_request(handle_, nullptr, nullptr); } AppControlResult AppControl::SendLaunchRequestWithReply( - std::shared_ptr> reply_sink, - AppControlChannel* manager) { - SetManager(manager); - auto on_reply = [](app_control_h request, app_control_h reply, - app_control_result_e result, void* user_data) { + ReplyCallback on_reply) { + auto reply_callback = [](app_control_h request, app_control_h reply, + app_control_result_e result, void* user_data) { AppControl* app_control = static_cast(user_data); - app_control_h clone = nullptr; - AppControlResult ret = app_control_clone(&clone, reply); - if (!ret) { - FT_LOG(Error) << "Could not clone app_control: " << ret.message(); - return; - } - - std::shared_ptr app_control_reply = - std::make_shared(clone); + auto app_control_reply = std::make_unique(reply); EncodableMap map; - map[EncodableValue("id")] = EncodableValue(app_control->GetId()); map[EncodableValue("reply")] = app_control_reply->SerializeAppControlToMap(); if (result == APP_CONTROL_RESULT_APP_STARTED) { @@ -250,15 +288,12 @@ AppControlResult AppControl::SendLaunchRequestWithReply( } else if (result == APP_CONTROL_RESULT_CANCELED) { map[EncodableValue("result")] = EncodableValue("canceled"); } - - app_control->reply_sink_->Success(EncodableValue(map)); - app_control->GetManager()->AddExistingAppControl( - std::move(app_control_reply)); + app_control->on_reply_(EncodableValue(map)); + app_control->on_reply_ = nullptr; + AppControlManager::GetInstance().Insert(std::move(app_control_reply)); }; - reply_sink_ = std::move(reply_sink); - AppControlResult ret = - app_control_send_launch_request(handle_, on_reply, this); - return ret; + on_reply_ = on_reply; + return app_control_send_launch_request(handle_, reply_callback, this); } AppControlResult AppControl::SendTerminateRequest() { @@ -266,7 +301,7 @@ AppControlResult AppControl::SendTerminateRequest() { return ret; } -AppControlResult AppControl::Reply(std::shared_ptr reply, +AppControlResult AppControl::Reply(AppControl* reply, const std::string& result) { app_control_result_e result_e; if (result == "appStarted") { @@ -281,7 +316,7 @@ AppControlResult AppControl::Reply(std::shared_ptr reply, return AppControlResult(APP_CONTROL_ERROR_INVALID_PARAMETER); } AppControlResult ret = app_control_reply_to_launch_request( - reply->Handle(), this->handle_, result_e); + reply->handle(), this->handle_, result_e); return ret; } diff --git a/shell/platform/tizen/channels/app_control.h b/shell/platform/tizen/channels/app_control.h index 24258254c5aea..94649d1b7451e 100644 --- a/shell/platform/tizen/channels/app_control.h +++ b/shell/platform/tizen/channels/app_control.h @@ -7,9 +7,34 @@ #include +#include + #include "flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/event_channel.h" -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/common/public/flutter_export.h" +#include "third_party/dart/runtime/include/dart_api_dl.h" + +// Called by Dart code through FFI to initialize dart_api_dl.h. +DART_EXPORT FLUTTER_EXPORT intptr_t NativeInitializeDartApi(void* data); + +// Creates an internally managed instance of AppControl and associates with +// |handle|. +// +// A finalizer is attached to the created instance and invoked when the +// associated |handle| is disposed by GC. +// +// Returns a unique AppControl ID on success, otherwise -1. +DART_EXPORT FLUTTER_EXPORT int32_t NativeCreateAppControl(Dart_Handle handle); + +// Finds an instance of AppControl with |id| and associates with |handle|. +// +// A finalizer is attached to the instance and invoked when the associated +// |handle| is disposed by GC. +// +// Returns false if an instance of AppControl with the given |id| could not +// be found, otherwise true. +DART_EXPORT FLUTTER_EXPORT bool NativeAttachAppControl(int32_t id, + Dart_Handle handle); namespace flutter { @@ -25,15 +50,16 @@ struct AppControlResult { int error_code; }; -class AppControlChannel; - class AppControl { public: - AppControl(app_control_h app_control); - ~AppControl(); + using ReplyCallback = std::function; + + explicit AppControl(); + explicit AppControl(app_control_h handle); + virtual ~AppControl(); - int GetId() { return id_; } - app_control_h Handle() { return handle_; } + int32_t id() { return id_; } + app_control_h handle() { return handle_; } AppControlResult GetOperation(std::string& operation); AppControlResult SetOperation(const std::string& operation); @@ -48,24 +74,19 @@ class AppControl { AppControlResult GetCaller(std::string& caller); AppControlResult GetLaunchMode(std::string& launch_mode); AppControlResult SetLaunchMode(const std::string& launch_mode); + bool IsReplyRequested(); EncodableValue SerializeAppControlToMap(); AppControlResult SendLaunchRequest(); - AppControlResult SendLaunchRequestWithReply( - std::shared_ptr> reply_sink, - AppControlChannel* manager); + AppControlResult SendLaunchRequestWithReply(ReplyCallback on_reply); AppControlResult SendTerminateRequest(); - AppControlResult Reply(std::shared_ptr reply, - const std::string& result); + AppControlResult Reply(AppControl* reply, const std::string& result); AppControlResult GetExtraData(EncodableMap& value); AppControlResult SetExtraData(const EncodableMap& value); - void SetManager(AppControlChannel* manager); - AppControlChannel* GetManager(); - private: AppControlResult GetString(std::string& str, int func(app_control_h, char**)); AppControlResult SetString(const std::string& str, @@ -74,12 +95,38 @@ class AppControl { AppControlResult AddExtraData(std::string key, EncodableValue value); AppControlResult AddExtraDataList(std::string& key, EncodableList& list); - app_control_h handle_; - int id_; - static int next_id_; - std::shared_ptr> reply_sink_; + app_control_h handle_ = nullptr; + int32_t id_; + static int32_t next_id_; + ReplyCallback on_reply_ = nullptr; +}; + +class AppControlManager { + public: + // Returns an instance of this class. + static AppControlManager& GetInstance() { + static AppControlManager instance; + return instance; + } + + void Insert(std::unique_ptr app_control) { + map_.insert({app_control->id(), std::move(app_control)}); + } + + void Remove(int32_t id) { map_.erase(id); } + + AppControl* FindById(const int32_t id) { + if (map_.find(id) == map_.end()) { + return nullptr; + } + return map_[id].get(); + } + + private: + explicit AppControlManager() {} + ~AppControlManager() {} - AppControlChannel* manager_; + std::unordered_map> map_; }; } // namespace flutter diff --git a/shell/platform/tizen/channels/app_control_channel.cc b/shell/platform/tizen/channels/app_control_channel.cc index c94132a69ee18..9ba1f2a3f55bc 100644 --- a/shell/platform/tizen/channels/app_control_channel.cc +++ b/shell/platform/tizen/channels/app_control_channel.cc @@ -7,6 +7,7 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/event_stream_handler_functions.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h" #include "flutter/shell/platform/tizen/channels/encodable_value_holder.h" +#include "flutter/shell/platform/tizen/logger.h" namespace flutter { @@ -14,7 +15,6 @@ namespace { constexpr char kChannelName[] = "tizen/internal/app_control_method"; constexpr char kEventChannelName[] = "tizen/internal/app_control_event"; -constexpr char kReplyChannelName[] = "tizen/internal/app_control_reply"; } // namespace @@ -43,44 +43,24 @@ AppControlChannel::AppControlChannel(BinaryMessenger* messenger) { }); event_channel_->SetStreamHandler(std::move(event_channel_handler)); - - reply_channel_ = std::make_unique>( - messenger, kReplyChannelName, &StandardMethodCodec::GetInstance()); - - auto reply_channel_handler = std::make_unique>( - [this](const EncodableValue* arguments, - std::unique_ptr>&& events) - -> std::unique_ptr> { - RegisterReplyHandler(std::move(events)); - return nullptr; - }, - [this](const EncodableValue* arguments) - -> std::unique_ptr> { - UnregisterReplyHandler(); - return nullptr; - }); - - reply_channel_->SetStreamHandler(std::move(reply_channel_handler)); } AppControlChannel::~AppControlChannel() {} -void AppControlChannel::NotifyAppControl(void* app_control) { - app_control_h clone = nullptr; - app_control_h handle = static_cast(app_control); - AppControlResult ret = app_control_clone(&clone, handle); - if (!ret) { - FT_LOG(Error) << "Could not clone app control: " << ret.message(); +void AppControlChannel::NotifyAppControl(void* handle) { + auto app_control = + std::make_unique(static_cast(handle)); + if (!app_control->handle()) { + FT_LOG(Error) << "Could not create an instance of AppControl."; return; } - auto app = std::make_shared(clone); if (!event_sink_) { - queue_.push(app); FT_LOG(Info) << "EventChannel not set yet."; + queue_.push(app_control.get()); } else { - SendAppControlDataEvent(app); + SendAppControlDataEvent(app_control.get()); } - map_.insert({app->GetId(), app}); + AppControlManager::GetInstance().Insert(std::move(app_control)); } void AppControlChannel::HandleMethodCall( @@ -134,58 +114,47 @@ void AppControlChannel::SendAlreadyQueuedEvents() { } } -void AppControlChannel::RegisterReplyHandler( - std::unique_ptr> events) { - reply_sink_ = std::move(events); -} - -void AppControlChannel::UnregisterReplyHandler() { - reply_sink_.reset(); -} - -std::shared_ptr AppControlChannel::GetAppControl( - const EncodableValue* arguments) { +AppControl* AppControlChannel::GetAppControl(const EncodableValue* arguments) { auto map_ptr = std::get_if(arguments); if (!map_ptr) { FT_LOG(Error) << "Invalid arguments."; return nullptr; } - EncodableValueHolder id(map_ptr, "id"); + EncodableValueHolder id(map_ptr, "id"); if (!id) { FT_LOG(Error) << "Could not get proper id from arguments."; return nullptr; } - if (map_.find(*id) == map_.end()) { + auto app_control = AppControlManager::GetInstance().FindById(*id); + if (!app_control) { FT_LOG(Error) << "Could not find AppControl with id " << *id; return nullptr; } - return map_[*id]; + return app_control; } void AppControlChannel::CreateAppControl( std::unique_ptr> result) { - app_control_h app_control = nullptr; - AppControlResult ret = app_control_create(&app_control); - if (!ret) { - result->Error("Could not create AppControl", ret.message()); + auto app_control = std::make_unique(); + if (app_control->handle()) { + result->Success(EncodableValue(app_control->id())); + AppControlManager::GetInstance().Insert(std::move(app_control)); + } else { + result->Error("Internal error", "Could not create AppControl."); } - auto app = std::make_unique(app_control); - int id = app->GetId(); - map_.insert({id, std::move(app)}); - result->Success(EncodableValue(id)); } void AppControlChannel::Dispose( - std::shared_ptr app_control, + AppControl* app_control, std::unique_ptr> result) { - map_.erase(app_control->GetId()); + AppControlManager::GetInstance().Remove(app_control->id()); result->Success(); } void AppControlChannel::Reply( - std::shared_ptr app_control, + AppControl* app_control, const EncodableValue* arguments, std::unique_ptr> result) { auto map_ptr = std::get_if(arguments); @@ -194,13 +163,19 @@ void AppControlChannel::Reply( return; } - EncodableValueHolder request_id(map_ptr, "requestId"); - if (!request_id || map_.find(*request_id) == map_.end()) { - result->Error("Could not reply", "Invalid request app control"); + EncodableValueHolder request_id(map_ptr, "requestId"); + if (!request_id) { + result->Error("Invalid arguments", "Invalid requestId parameter"); + return; + } + auto request_app_control = + AppControlManager::GetInstance().FindById(*request_id); + if (!request_app_control) { + result->Error("Invalid arguments", + "Could not find AppControl with the given ID."); return; } - auto request_app_control = map_[*request_id]; EncodableValueHolder result_str(map_ptr, "result"); if (!result_str) { result->Error("Could not reply", "Invalid result parameter"); @@ -215,7 +190,7 @@ void AppControlChannel::Reply( } void AppControlChannel::SendLaunchRequest( - std::shared_ptr app_control, + AppControl* app_control, const EncodableValue* arguments, std::unique_ptr> result) { auto map_ptr = std::get_if(arguments); @@ -225,23 +200,29 @@ void AppControlChannel::SendLaunchRequest( } EncodableValueHolder wait_for_reply(map_ptr, "waitForReply"); - - AppControlResult ret; if (wait_for_reply && *wait_for_reply) { - ret = app_control->SendLaunchRequestWithReply(std::move(reply_sink_), this); - } else { - ret = app_control->SendLaunchRequest(); - } - - if (ret) { - result->Success(); + auto result_ptr = result.release(); + auto on_reply = [result_ptr](const EncodableValue& response) { + result_ptr->Success(response); + delete result_ptr; + }; + AppControlResult ret = app_control->SendLaunchRequestWithReply(on_reply); + if (!ret) { + result_ptr->Error(ret.message()); + delete result_ptr; + } } else { - result->Error(ret.message()); + AppControlResult ret = app_control->SendLaunchRequest(); + if (ret) { + result->Success(); + } else { + result->Error(ret.message()); + } } } void AppControlChannel::SendTerminateRequest( - std::shared_ptr app_control, + AppControl* app_control, std::unique_ptr> result) { AppControlResult ret = app_control->SendTerminateRequest(); if (ret) { @@ -252,7 +233,7 @@ void AppControlChannel::SendTerminateRequest( } void AppControlChannel::SetAppControlData( - std::shared_ptr app_control, + AppControl* app_control, const EncodableValue* arguments, std::unique_ptr> result) { auto map_ptr = std::get_if(arguments); @@ -301,8 +282,7 @@ void AppControlChannel::SetAppControlData( result->Success(); } -void AppControlChannel::SendAppControlDataEvent( - std::shared_ptr app_control) { +void AppControlChannel::SendAppControlDataEvent(AppControl* app_control) { EncodableValue map = app_control->SerializeAppControlToMap(); if (!map.IsNull()) { event_sink_->Success(map); diff --git a/shell/platform/tizen/channels/app_control_channel.h b/shell/platform/tizen/channels/app_control_channel.h index cbaa40884e231..6663cbe261687 100644 --- a/shell/platform/tizen/channels/app_control_channel.h +++ b/shell/platform/tizen/channels/app_control_channel.h @@ -7,14 +7,12 @@ #include #include -#include #include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/event_channel.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h" #include "flutter/shell/platform/tizen/channels/app_control.h" -#include "flutter/shell/platform/tizen/logger.h" namespace flutter { @@ -25,10 +23,6 @@ class AppControlChannel { void NotifyAppControl(void* app_control); - void AddExistingAppControl(std::shared_ptr app_control) { - map_.insert({app_control->GetId(), app_control}); - } - private: void HandleMethodCall(const MethodCall& method_call, std::unique_ptr> result); @@ -36,42 +30,35 @@ class AppControlChannel { void UnregisterEventHandler(); void SendAlreadyQueuedEvents(); - void RegisterReplyHandler(std::unique_ptr> events); - void UnregisterReplyHandler(); - - std::shared_ptr GetAppControl(const EncodableValue* arguments); + AppControl* GetAppControl(const EncodableValue* arguments); void CreateAppControl(std::unique_ptr> result); - void Dispose(std::shared_ptr app_control, + void Dispose(AppControl* app_control, std::unique_ptr> result); - void Reply(std::shared_ptr app_control, + void Reply(AppControl* app_control, const EncodableValue* arguments, std::unique_ptr> result); - void SendLaunchRequest(std::shared_ptr app_control, + void SendLaunchRequest(AppControl* app_control, const EncodableValue* arguments, std::unique_ptr> result); void SendTerminateRequest( - std::shared_ptr app_control, + AppControl* app_control, std::unique_ptr> result); - void SetAppControlData(std::shared_ptr app_control, + void SetAppControlData(AppControl* app_control, const EncodableValue* arguments, std::unique_ptr> result); - void SendAppControlDataEvent(std::shared_ptr app_control); + void SendAppControlDataEvent(AppControl* app_control); std::unique_ptr> method_channel_; std::unique_ptr> event_channel_; - std::unique_ptr> reply_channel_; std::unique_ptr> event_sink_; - std::shared_ptr> reply_sink_; // We need this queue, because there is no quarantee // that EventChannel on Dart side will be registered // before native OnAppControl event - std::queue> queue_; - - std::unordered_map> map_; + std::queue queue_; }; } // namespace flutter