diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn index 2f9f9199b4e6f..6fa61355bb865 100644 --- a/shell/platform/tizen/BUILD.gn +++ b/shell/platform/tizen/BUILD.gn @@ -150,6 +150,8 @@ template("embedder") { if (embedder_for_target) { sources += [ + "channels/app_control.cc", + "channels/app_control_channel.cc", "channels/platform_channel.cc", "channels/settings_channel.cc", "channels/settings_channel_tizen.cc", @@ -162,6 +164,7 @@ template("embedder") { "base-utils-i18n", "capi-appfw-application", "capi-appfw-app-common", + "capi-appfw-app-control", "capi-base-common", "capi-system-info", "capi-system-system-settings", diff --git a/shell/platform/tizen/channels/app_control.cc b/shell/platform/tizen/channels/app_control.cc new file mode 100644 index 0000000000000..b16a7bd0e0fe4 --- /dev/null +++ b/shell/platform/tizen/channels/app_control.cc @@ -0,0 +1,324 @@ +// Copyright 2021 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 "app_control.h" +#include "flutter/shell/platform/common/client_wrapper/include/flutter/event_stream_handler_functions.h" +#include "flutter/shell/platform/tizen/channels/app_control_channel.h" + +namespace flutter { + +int AppControl::next_id_ = 0; + +AppControl::AppControl(app_control_h app_control) : id_(next_id_++) { + handle_ = app_control; +} + +AppControl::~AppControl() { + app_control_destroy(handle_); +} + +AppControlResult AppControl::GetString(std::string& str, + int func(app_control_h, char**)) { + char* op; + AppControlResult ret = func(handle_, &op); + if (!ret) { + return ret; + } + if (op != nullptr) { + str = std::string{op}; + free(op); + } else { + str = ""; + } + return AppControlResult(APP_CONTROL_ERROR_NONE); +} + +AppControlResult AppControl::SetString(const std::string& str, + int func(app_control_h, const char*)) { + int ret = func(handle_, str.c_str()); + return AppControlResult(ret); +} + +bool OnAppControlExtraDataCallback(app_control_h app, + const char* key, + void* user_data) { + auto extra_data = static_cast(user_data); + bool is_array = false; + int ret = app_control_is_extra_data_array(app, key, &is_array); + if (ret != APP_CONTROL_ERROR_NONE) { + FT_LOG(Error) << "app_control_is_extra_data_array() failed at key " << key; + return false; + } + + if (is_array) { + char** strings = nullptr; + int length = 0; + ret = app_control_get_extra_data_array(app, key, &strings, &length); + if (ret != APP_CONTROL_ERROR_NONE) { + FT_LOG(Error) << "app_control_get_extra_data_array() failed at key " + << key; + return false; + } + EncodableList list; + for (int i = 0; i < length; i++) { + list.push_back(EncodableValue(std::string(strings[i]))); + free(strings[i]); + } + free(strings); + extra_data->insert( + {EncodableValue(std::string(key)), EncodableValue(list)}); + } else { + char* value = nullptr; + ret = app_control_get_extra_data(app, key, &value); + if (ret != APP_CONTROL_ERROR_NONE) { + FT_LOG(Error) << "app_control_get_extra_data() failed at key " << key; + return false; + } + extra_data->insert( + {EncodableValue(std::string(key)), EncodableValue(std::string(value))}); + free(value); + } + + return true; +} + +AppControlResult AppControl::GetExtraData(EncodableMap& value) { + EncodableMap extra_data; + int ret = app_control_foreach_extra_data( + handle_, OnAppControlExtraDataCallback, &extra_data); + if (ret == APP_CONTROL_ERROR_NONE) { + value = std::move(extra_data); + } + return AppControlResult(ret); +} + +AppControlResult AppControl::SetExtraData(const EncodableMap& map) { + for (const auto& v : map) { + if (!std::holds_alternative(v.first)) { + FT_LOG(Error) << "Key for extra data has to be string, omitting"; + continue; + } + std::string key = std::get(v.first); + AppControlResult ret = AddExtraData(key, v.second); + if (!ret) { + FT_LOG(Error) << "Invalid data at " << key << ", omitting"; + continue; + } + } + return AppControlResult(); +} + +void AppControl::SetManager(AppControlChannel* m) { + manager_ = m; +} + +AppControlChannel* AppControl::GetManager() { + return manager_; +} + +AppControlResult AppControl::GetOperation(std::string& operation) { + return GetString(operation, app_control_get_operation); +} + +AppControlResult AppControl::SetOperation(const std::string& operation) { + return SetString(operation, app_control_set_operation); +} + +AppControlResult AppControl::GetUri(std::string& uri) { + return GetString(uri, app_control_get_uri); +} + +AppControlResult AppControl::SetUri(const std::string& uri) { + return SetString(uri, app_control_set_uri); +} + +AppControlResult AppControl::GetMime(std::string& mime) { + return GetString(mime, app_control_get_mime); +} + +AppControlResult AppControl::SetMime(const std::string& mime) { + return SetString(mime, app_control_set_mime); +} + +AppControlResult AppControl::GetCategory(std::string& category) { + return GetString(category, app_control_get_category); +} + +AppControlResult AppControl::SetCategory(const std::string& category) { + return SetString(category, app_control_set_category); +} + +AppControlResult AppControl::GetAppId(std::string& app_id) { + return GetString(app_id, app_control_get_app_id); +} + +AppControlResult AppControl::SetAppId(const std::string& app_id) { + return SetString(app_id, app_control_set_app_id); +} + +AppControlResult AppControl::GetCaller(std::string& caller) { + return GetString(caller, app_control_get_caller); +} + +AppControlResult AppControl::GetLaunchMode(std::string& launch_mode) { + app_control_launch_mode_e launch_mode_e; + int ret = app_control_get_launch_mode(handle_, &launch_mode_e); + if (ret != APP_CONTROL_ERROR_NONE) { + return AppControlResult(ret); + } + launch_mode = + (launch_mode_e == APP_CONTROL_LAUNCH_MODE_SINGLE ? "single" : "group"); + return AppControlResult(APP_CONTROL_ERROR_NONE); +} + +AppControlResult AppControl::SetLaunchMode(const std::string& launch_mode) { + app_control_launch_mode_e launch_mode_e; + if (launch_mode.compare("single")) { + launch_mode_e = APP_CONTROL_LAUNCH_MODE_SINGLE; + } else { + launch_mode_e = APP_CONTROL_LAUNCH_MODE_GROUP; + } + int ret = app_control_set_launch_mode(handle_, launch_mode_e); + return AppControlResult(ret); +} + +EncodableValue AppControl::SerializeAppControlToMap() { + std::string app_id, operation, mime, category, uri, caller_id, launch_mode; + AppControlResult results[7]; + results[0] = GetAppId(app_id); + results[1] = GetOperation(operation); + results[2] = GetMime(mime); + results[3] = GetCategory(category); + results[4] = GetUri(uri); + results[5] = GetLaunchMode(launch_mode); + // Caller Id is optional. + GetCaller(caller_id); + EncodableMap extra_data; + results[6] = GetExtraData(extra_data); + for (int i = 0; i < 7; i++) { + if (!results[i]) { + return EncodableValue(); + } + } + EncodableMap map; + map[EncodableValue("id")] = EncodableValue(GetId()); + 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("launchMode")] = EncodableValue(launch_mode); + map[EncodableValue("extraData")] = EncodableValue(extra_data); + + return EncodableValue(map); +} + +AppControlResult AppControl::SendLaunchRequest() { + AppControlResult ret = + app_control_send_launch_request(handle_, nullptr, nullptr); + return ret; +} + +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) { + 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); + EncodableMap map; + map[EncodableValue("id")] = EncodableValue(app_control->GetId()); + map[EncodableValue("reply")] = + app_control_reply->SerializeAppControlToMap(); + if (result == APP_CONTROL_RESULT_APP_STARTED) { + map[EncodableValue("result")] = EncodableValue("appStarted"); + } else if (result == APP_CONTROL_RESULT_SUCCEEDED) { + map[EncodableValue("result")] = EncodableValue("succeeded"); + } else if (result == APP_CONTROL_RESULT_FAILED) { + map[EncodableValue("result")] = EncodableValue("failed"); + } else if (result == APP_CONTROL_RESULT_CANCELED) { + map[EncodableValue("result")] = EncodableValue("cancelled"); + } + + app_control->reply_sink_->Success(EncodableValue(map)); + app_control->GetManager()->AddExistingAppControl( + std::move(app_control_reply)); + }; + reply_sink_ = std::move(reply_sink); + AppControlResult ret = + app_control_send_launch_request(handle_, on_reply, this); + return ret; +} + +AppControlResult AppControl::SendTerminateRequest() { + AppControlResult ret = app_control_send_terminate_request(handle_); + return ret; +} + +AppControlResult AppControl::Reply(std::shared_ptr reply, + const std::string& result) { + app_control_result_e result_e; + if (result == "appStarted") { + result_e = APP_CONTROL_RESULT_APP_STARTED; + } else if (result == "succeeded") { + result_e = APP_CONTROL_RESULT_SUCCEEDED; + } else if (result == "failed") { + result_e = APP_CONTROL_RESULT_FAILED; + } else if (result == "cancelled") { + result_e = APP_CONTROL_RESULT_CANCELED; + } else { + return AppControlResult(APP_CONTROL_ERROR_INVALID_PARAMETER); + } + AppControlResult ret = app_control_reply_to_launch_request( + reply->Handle(), this->handle_, result_e); + return ret; +} + +AppControlResult AppControl::AddExtraData(std::string key, + EncodableValue value) { + bool is_array = std::holds_alternative(value); + if (is_array) { + EncodableList& list = std::get(value); + return AddExtraDataList(key, list); + } else { + bool is_string = std::holds_alternative(value); + if (is_string) { + int ret = app_control_add_extra_data( + handle_, key.c_str(), std::get(value).c_str()); + return AppControlResult(ret); + } else { + return AppControlResult(APP_ERROR_INVALID_PARAMETER); + } + } + return AppControlResult(APP_CONTROL_ERROR_NONE); +} + +AppControlResult AppControl::AddExtraDataList(std::string& key, + EncodableList& list) { + size_t length = list.size(); + auto strings = std::vector(length); + for (size_t i = 0; i < length; i++) { + bool is_string = std::holds_alternative(list[i]); + if (is_string) { + strings[i] = std::get(list[i]).c_str(); + } else { + return AppControlResult(APP_ERROR_INVALID_PARAMETER); + } + } + int ret = app_control_add_extra_data_array(handle_, key.c_str(), + strings.data(), length); + return AppControlResult(ret); +} + +} // namespace flutter diff --git a/shell/platform/tizen/channels/app_control.h b/shell/platform/tizen/channels/app_control.h new file mode 100644 index 0000000000000..ac6c55fd9a4cc --- /dev/null +++ b/shell/platform/tizen/channels/app_control.h @@ -0,0 +1,92 @@ +// Copyright 2021 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_APP_CONTROL_H_ +#define EMBEDDER_APP_CONTROL_H_ + +#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/common/client_wrapper/include/flutter/standard_method_codec.h" +#include "flutter/shell/platform/tizen/logger.h" + +namespace flutter { + +struct AppControlResult { + AppControlResult() : error_code(APP_CONTROL_ERROR_NONE){}; + AppControlResult(int code) : error_code(code) {} + + // Returns false on error. + operator bool() const { return (APP_CONTROL_ERROR_NONE == error_code); } + + std::string message() { return get_error_message(error_code); } + + int error_code; +}; + +class AppControlChannel; + +class AppControl { + public: + AppControl(app_control_h app_control); + ~AppControl(); + + int GetId() { return id_; } + app_control_h Handle() { return handle_; } + + AppControlResult GetOperation(std::string& operation); + AppControlResult SetOperation(const std::string& operation); + AppControlResult GetUri(std::string& uri); + AppControlResult SetUri(const std::string& uri); + AppControlResult GetMime(std::string& mime); + AppControlResult SetMime(const std::string& mime); + AppControlResult GetCategory(std::string& category); + AppControlResult SetCategory(const std::string& category); + AppControlResult GetAppId(std::string& app_id); + AppControlResult SetAppId(const std::string& app_id); + AppControlResult GetCaller(std::string& caller); + AppControlResult GetLaunchMode(std::string& launch_mode); + AppControlResult SetLaunchMode(const std::string& launch_mode); + + EncodableValue SerializeAppControlToMap(); + + AppControlResult SendLaunchRequest(); + AppControlResult SendLaunchRequestWithReply( + std::shared_ptr> reply_sink, + AppControlChannel* manager); + AppControlResult SendTerminateRequest(); + + AppControlResult Reply(std::shared_ptr 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, + int func(app_control_h, const char*)); + + 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_; + + AppControlChannel* manager_; +}; + +} // namespace flutter + +#endif // EMBEDDER_APP_CONTROL_H_ diff --git a/shell/platform/tizen/channels/app_control_channel.cc b/shell/platform/tizen/channels/app_control_channel.cc new file mode 100644 index 0000000000000..5b85193d2317a --- /dev/null +++ b/shell/platform/tizen/channels/app_control_channel.cc @@ -0,0 +1,303 @@ +// Copyright 2021 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 + +#include "app_control.h" +#include "app_control_channel.h" + +#include "flutter/shell/platform/common/client_wrapper/include/flutter/event_stream_handler_functions.h" + +namespace flutter { + +static constexpr char kChannelName[] = "tizen/internal/app_control_method"; +static constexpr char kEventChannelName[] = "tizen/internal/app_control_event"; +static constexpr char kReplyChannelName[] = "tizen/internal/app_control_reply"; + +AppControlChannel::AppControlChannel(BinaryMessenger* messenger) { + method_channel_ = std::make_unique>( + messenger, kChannelName, &StandardMethodCodec::GetInstance()); + + method_channel_->SetMethodCallHandler([this](const auto& call, auto result) { + this->HandleMethodCall(call, std::move(result)); + }); + + event_channel_ = std::make_unique>( + messenger, kEventChannelName, &StandardMethodCodec::GetInstance()); + + auto event_channel_handler = std::make_unique>( + [this](const EncodableValue* arguments, + std::unique_ptr>&& events) + -> std::unique_ptr> { + RegisterEventHandler(std::move(events)); + return nullptr; + }, + [this](const EncodableValue* arguments) + -> std::unique_ptr> { + UnregisterEventHandler(); + return nullptr; + }); + + 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(); + return; + } + auto app = std::make_shared(clone); + if (!event_sink_) { + queue_.push(app); + FT_LOG(Info) << "EventChannel not set yet."; + } else { + SendAppControlDataEvent(app); + } + map_.insert({app->GetId(), app}); +} + +void AppControlChannel::HandleMethodCall( + const MethodCall& method_call, + std::unique_ptr> result) { + const auto arguments = method_call.arguments(); + const auto& method_name = method_call.method_name(); + + // AppControl is not needed. + if (method_name.compare("create") == 0) { + CreateAppControl(arguments, std::move(result)); + return; + } + + // AppControl is needed. + auto app_control = GetAppControl(arguments); + if (app_control == nullptr) { + result->Error("Could not find app_control", "Invalid id provided"); + return; + } + + if (method_name.compare("dispose") == 0) { + Dispose(app_control, std::move(result)); + } else if (method_name.compare("reply") == 0) { + Reply(app_control, arguments, std::move(result)); + } else if (method_name.compare("sendLaunchRequest") == 0) { + SendLaunchRequest(app_control, arguments, std::move(result)); + } else if (method_name.compare("setAppControlData") == 0) { + SetAppControlData(app_control, arguments, std::move(result)); + } else if (method_name.compare("sendTerminateRequest") == 0) { + SendTerminateRequest(app_control, arguments, std::move(result)); + } else { + result->NotImplemented(); + } +} + +void AppControlChannel::RegisterEventHandler( + std::unique_ptr> events) { + event_sink_ = std::move(events); + SendAlreadyQueuedEvents(); +} + +void AppControlChannel::UnregisterEventHandler() { + event_sink_.reset(); +} + +void AppControlChannel::SendAlreadyQueuedEvents() { + while (!queue_.empty()) { + SendAppControlDataEvent(queue_.front()); + queue_.pop(); + } +} + +void AppControlChannel::RegisterReplyHandler( + std::unique_ptr> events) { + reply_sink_ = std::move(events); +} + +void AppControlChannel::UnregisterReplyHandler() { + reply_sink_.reset(); +} + +template +bool AppControlChannel::GetValueFromArgs(const EncodableValue* args, + const char* key, + T& out) { + if (std::holds_alternative(*args)) { + EncodableMap map = std::get(*args); + if (map.find(EncodableValue(key)) != map.end()) { + EncodableValue value = map[EncodableValue(key)]; + if (std::holds_alternative(value)) { + out = std::get(value); + return true; + } + } + FT_LOG(Info) << "Key " << key << " not found."; + } + return false; +} + +std::shared_ptr AppControlChannel::GetAppControl( + const EncodableValue* args) { + int id; + if (!GetValueFromArgs(args, "id", id)) { + FT_LOG(Error) << "Could not get proper id from arguments."; + return nullptr; + } + + if (map_.find(id) == map_.end()) { + FT_LOG(Error) << "Could not find AppControl with id " << id; + return nullptr; + } + return map_[id]; +} + +void AppControlChannel::CreateAppControl( + const EncodableValue* args, + 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 = 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, + std::unique_ptr> result) { + map_.erase(app_control->GetId()); + result->Success(); +} + +void AppControlChannel::Reply( + std::shared_ptr app_control, + const EncodableValue* arguments, + std::unique_ptr> result) { + int request_id; + if (!GetValueFromArgs(arguments, "requestId", request_id) || + map_.find(request_id) == map_.end()) { + result->Error("Could not reply", "Invalid request app control"); + return; + } + + auto request_app_control = map_[request_id]; + std::string result_str; + if (!GetValueFromArgs(arguments, "result", result_str)) { + result->Error("Could not reply", "Invalid result parameter"); + return; + } + AppControlResult ret = app_control->Reply(request_app_control, result_str); + if (ret) { + result->Success(); + } else { + result->Error("Could not reply to app control", ret.message()); + } +} + +void AppControlChannel::SendLaunchRequest( + std::shared_ptr app_control, + const EncodableValue* arguments, + std::unique_ptr> result) { + bool wait_for_reply = false; + GetValueFromArgs(arguments, "waitForReply", wait_for_reply); + AppControlResult ret; + if (wait_for_reply) { + ret = app_control->SendLaunchRequestWithReply(std::move(reply_sink_), this); + } else { + ret = app_control->SendLaunchRequest(); + } + + if (ret) { + result->Success(); + } else { + result->Error(ret.message()); + } +} + +void AppControlChannel::SendTerminateRequest( + std::shared_ptr app_control, + const EncodableValue* arguments, + std::unique_ptr> result) { + AppControlResult ret = app_control->SendTerminateRequest(); + if (ret) { + result->Success(); + } else { + result->Error("Could not terminate", ret.message()); + } +} + +void AppControlChannel::SetAppControlData( + std::shared_ptr app_control, + const EncodableValue* arguments, + std::unique_ptr> result) { + std::string app_id, operation, mime, category, uri, launch_mode; + EncodableMap extra_data; + GetValueFromArgs(arguments, "appId", app_id); + GetValueFromArgs(arguments, "operation", operation); + GetValueFromArgs(arguments, "mime", mime); + GetValueFromArgs(arguments, "category", category); + GetValueFromArgs(arguments, "launchMode", launch_mode); + GetValueFromArgs(arguments, "uri", uri); + GetValueFromArgs(arguments, "extraData", extra_data); + + AppControlResult results[7]; + results[0] = app_control->SetAppId(app_id); + if (!operation.empty()) { + results[1] = app_control->SetOperation(operation); + } + if (!mime.empty()) { + results[2] = app_control->SetMime(mime); + } + if (!category.empty()) { + results[3] = app_control->SetCategory(category); + } + if (!uri.empty()) { + results[4] = app_control->SetUri(uri); + } + if (!launch_mode.empty()) { + results[5] = app_control->SetLaunchMode(launch_mode); + } + results[6] = app_control->SetExtraData(extra_data); + for (int i = 0; i < 7; i++) { + if (!results[i]) { + result->Error("Could not set value for app control", + results[i].message()); + } + } + result->Success(); +} + +void AppControlChannel::SendAppControlDataEvent( + std::shared_ptr app_control) { + EncodableValue map = app_control->SerializeAppControlToMap(); + if (!map.IsNull()) { + event_sink_->Success(map); + } +} + +} // namespace flutter diff --git a/shell/platform/tizen/channels/app_control_channel.h b/shell/platform/tizen/channels/app_control_channel.h new file mode 100644 index 0000000000000..c94bd3de3c70b --- /dev/null +++ b/shell/platform/tizen/channels/app_control_channel.h @@ -0,0 +1,87 @@ +// Copyright 2021 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_APP_CONTROL_CHANNEL_H_ +#define EMBEDDER_APP_CONTROL_CHANNEL_H_ + +#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/common/client_wrapper/include/flutter/standard_method_codec.h" +#include "flutter/shell/platform/tizen/logger.h" + +#include "app_control.h" + +namespace flutter { + +class AppControlChannel { + public: + explicit AppControlChannel(BinaryMessenger* messenger); + virtual ~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); + void RegisterEventHandler( + std::unique_ptr> events); + void UnregisterEventHandler(); + void SendAlreadyQueuedEvents(); + + void RegisterReplyHandler( + std::unique_ptr> events); + void UnregisterReplyHandler(); + + template + bool GetValueFromArgs(const EncodableValue* args, const char* key, T& out); + + std::shared_ptr GetAppControl(const EncodableValue* args); + + void CreateAppControl(const EncodableValue* args, + std::unique_ptr> result); + + void Dispose(std::shared_ptr app_control, + std::unique_ptr> result); + void Reply(std::shared_ptr app_control, + const EncodableValue* arguments, + std::unique_ptr> result); + void SendLaunchRequest(std::shared_ptr app_control, + const EncodableValue* arguments, + std::unique_ptr> result); + void SendTerminateRequest( + std::shared_ptr app_control, + const EncodableValue* arguments, + std::unique_ptr> result); + + void SetAppControlData(std::shared_ptr app_control, + const EncodableValue* arguments, + std::unique_ptr> result); + void SendAppControlDataEvent(std::shared_ptr 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_; +}; + +} // namespace flutter + +#endif // EMBEDDER_APP_CONTROL_CHANNEL_H_ diff --git a/shell/platform/tizen/flutter_tizen.cc b/shell/platform/tizen/flutter_tizen.cc index 1cc45c85cf144..e08b7f182888f 100644 --- a/shell/platform/tizen/flutter_tizen.cc +++ b/shell/platform/tizen/flutter_tizen.cc @@ -118,6 +118,13 @@ void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger, user_data); } +void FlutterDesktopNotifyAppControl(FlutterDesktopEngineRef engine, + void* app_control) { +#ifndef __X64_SHELL__ + EngineFromHandle(engine)->app_control_channel->NotifyAppControl(app_control); +#endif +} + void FlutterDesktopNotifyLocaleChange(FlutterDesktopEngineRef engine) { EngineFromHandle(engine)->SetupLocales(); } diff --git a/shell/platform/tizen/flutter_tizen_engine.cc b/shell/platform/tizen/flutter_tizen_engine.cc index 91b112b044d98..e298df89166fd 100644 --- a/shell/platform/tizen/flutter_tizen_engine.cc +++ b/shell/platform/tizen/flutter_tizen_engine.cc @@ -243,6 +243,10 @@ bool FlutterTizenEngine::RunEngine(const char* entrypoint) { internal_plugin_registrar_ = std::make_unique(plugin_registrar_.get()); +#ifndef __X64_SHELL__ + app_control_channel = std::make_unique( + internal_plugin_registrar_->messenger()); +#endif platform_channel = std::make_unique( internal_plugin_registrar_->messenger(), renderer.get()); settings_channel = std::make_unique( diff --git a/shell/platform/tizen/flutter_tizen_engine.h b/shell/platform/tizen/flutter_tizen_engine.h index 92294e5bf88b9..5fe82def58503 100644 --- a/shell/platform/tizen/flutter_tizen_engine.h +++ b/shell/platform/tizen/flutter_tizen_engine.h @@ -11,6 +11,9 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" #include "flutter/shell/platform/common/incoming_message_dispatcher.h" #include "flutter/shell/platform/embedder/embedder.h" +#ifndef __X64_SHELL__ +#include "flutter/shell/platform/tizen/channels/app_control_channel.h" +#endif #include "flutter/shell/platform/tizen/channels/key_event_channel.h" #include "flutter/shell/platform/tizen/channels/lifecycle_channel.h" #include "flutter/shell/platform/tizen/channels/navigation_channel.h" @@ -137,6 +140,9 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { std::unique_ptr renderer; // The system channels for communicating between Flutter and the platform. +#ifndef __X64_SHELL__ + std::unique_ptr app_control_channel; +#endif std::unique_ptr key_event_channel; std::unique_ptr lifecycle_channel; std::unique_ptr navigation_channel; diff --git a/shell/platform/tizen/public/flutter_tizen.h b/shell/platform/tizen/public/flutter_tizen.h index a0a70da83c47a..f7e1f90024765 100644 --- a/shell/platform/tizen/public/flutter_tizen.h +++ b/shell/platform/tizen/public/flutter_tizen.h @@ -89,6 +89,11 @@ FlutterDesktopGetPluginRegistrar(FlutterDesktopEngineRef engine, FLUTTER_EXPORT FlutterDesktopMessengerRef FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine); +// Posts an app control to the engine instance. +FLUTTER_EXPORT void FlutterDesktopNotifyAppControl( + FlutterDesktopEngineRef engine, + void* app_control); + // Posts a locale change notification to the engine instance. FLUTTER_EXPORT void FlutterDesktopNotifyLocaleChange( FlutterDesktopEngineRef engine);