From 04353875a73cab2491629a916195e93f56db6aa4 Mon Sep 17 00:00:00 2001
From: "Piotr Kosko/Tizen API (PLT) /SRPOL/Engineer/Samsung Electronics"
Date: Wed, 14 Apr 2021 10:18:21 +0200
Subject: [PATCH] [Clipboard] getData implementation added
[Before] Clipboard.getData feature was not implemented
[After] Dart code below is able to gather system clipboard data:
Future d = Clipboard.getData(Clipboard.kTextPlain);
void dataCallback(ClipboardData? d) {
if (d != null) {
String? text = d.text;
if(text != null) {
print("Clipboard data $text");
}
}
}
d.then(dataCallback);
[TODO] Need to consider adding some mechanism of synchronization of access to native cbhm API
to provide proper behaviour in case of multiple calls
---
shell/platform/tizen/BUILD.gn | 4 +-
.../tizen/channels/platform_channel.cc | 106 +++++++++++++++++-
2 files changed, 108 insertions(+), 2 deletions(-)
diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn
index 5cdac760a2ac3..cc3f416dd8d5a 100644
--- a/shell/platform/tizen/BUILD.gn
+++ b/shell/platform/tizen/BUILD.gn
@@ -87,7 +87,8 @@ source_set("flutter_tizen") {
"$custom_sysroot/usr/include/eo-1",
"$custom_sysroot/usr/include/evas-1",
"$custom_sysroot/usr/include/system",
- "$custom_sysroot/usr/include/wayland-extension"
+ "$custom_sysroot/usr/include/wayland-extension",
+ "$custom_sysroot/usr/include/cbhm",
]
lib_dirs = [ root_out_dir, "$custom_sysroot/usr/lib" ]
@@ -114,6 +115,7 @@ source_set("flutter_tizen") {
"tbm",
"tdm-client",
"wayland-client",
+ "cbhm",
]
if (tizen_sdk_4) {
diff --git a/shell/platform/tizen/channels/platform_channel.cc b/shell/platform/tizen/channels/platform_channel.cc
index b79f780af3a52..86dfdd22b33a3 100644
--- a/shell/platform/tizen/channels/platform_channel.cc
+++ b/shell/platform/tizen/channels/platform_channel.cc
@@ -4,13 +4,25 @@
#include "platform_channel.h"
+#include
#include
+#include
#include "flutter/shell/platform/common/cpp/json_method_codec.h"
#include "flutter/shell/platform/tizen/tizen_log.h"
static constexpr char kChannelName[] = "flutter/platform";
+// Clipboard.getData constants and variables
+std::mutex is_processing_mutex;
+static bool is_processing = false;
+static constexpr char kTextKey[] = "text";
+static constexpr char kTextPlainFormat[] = "text/plain";
+static constexpr char kUnknownClipboardFormatError[] =
+ "Unknown clipboard format error";
+static constexpr char kUnknownClipboardError[] =
+ "Unknown error during clipboard data retrieval";
+
PlatformChannel::PlatformChannel(flutter::BinaryMessenger* messenger)
: channel_(std::make_unique>(
messenger, kChannelName, &flutter::JsonMethodCodec::GetInstance())) {
@@ -37,7 +49,99 @@ void PlatformChannel::HandleMethodCall(
} else if (method == "HapticFeedback.vibrate") {
result->NotImplemented();
} else if (method == "Clipboard.getData") {
- result->NotImplemented();
+ const rapidjson::Value& format = call.arguments()[0];
+
+ // https://api.flutter.dev/flutter/services/Clipboard/kTextPlain-constant.html
+ // API supports only kTextPlain format, however cbhm API supports also other formats
+ if (strcmp(format.GetString(), kTextPlainFormat) != 0) {
+ result->Error(kUnknownClipboardFormatError,
+ "Clipboard API only supports text.");
+ return;
+ }
+
+ // Report error on next calls until current will be finished.
+ // Native API - cbhm_selection_get works on static struct, so accessing clipboard parallelly will end
+ // with race regarding returning values - cbhm_selection_data_cb will be triggered only for latest call.
+ // TODO consider some queuing mechnism instead of returning error for next calls
+ {
+ std::lock_guard lock(is_processing_mutex);
+ if (is_processing) {
+ result->Error(kUnknownClipboardError, "Already processing by other thread.");
+ return;
+ }
+ is_processing = true;
+ }
+
+ cbhm_sel_type_e selection_type = CBHM_SEL_TYPE_TEXT;
+
+ cbhm_h cbhm_handle = nullptr;
+ int ret = cbhm_open_service (&cbhm_handle);
+ if (CBHM_ERROR_NONE != ret) {
+ result->Error(kUnknownClipboardError, "Failed to initialize cbhm service.");
+ return;
+ }
+
+ // additional check if data in clipboard
+ ret = cbhm_item_count_get(cbhm_handle);
+ if (ret <= 0) {
+ result->Error(kUnknownClipboardError, "No clipboard data available.");
+ // release the data
+ cbhm_close_service (cbhm_handle);
+ // unlock guard for further processing
+ std::lock_guard lock(is_processing_mutex);
+ is_processing = false;
+ return;
+ }
+
+ struct method_data_t {
+ std::unique_ptr> result;
+ cbhm_h cbhm_handle;
+ };
+ // invalidates the result pointer
+ method_data_t* data = new method_data_t{};
+ data->result = std::move(result);
+ data->cbhm_handle = cbhm_handle;
+
+ auto cbhm_selection_data_cb = [](cbhm_h cbhm_handle, const char *buf, size_t len, void *user_data) -> int {
+ auto data = static_cast(user_data);
+ // move unique_ptr from method_data_t and then release memory
+ auto result = std::move(data->result);
+ cbhm_close_service (data->cbhm_handle);
+ delete data;
+
+ FT_LOGD("cbhm_selection_get SUCCESS (%d) %s", len, buf);
+ {
+ std::lock_guard lock(is_processing_mutex);
+ is_processing = false;
+ }
+ if (buf) {
+ rapidjson::Document document;
+ document.SetObject();
+ rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
+ document.AddMember(rapidjson::Value(kTextKey, allocator),
+ rapidjson::Value(std::string{buf, len}, allocator), allocator);
+ result->Success(document);
+ return CBHM_ERROR_NONE;
+ } else {
+ result->Error(kUnknownClipboardError, "Data buffer is null.");
+ return CBHM_ERROR_NO_DATA;
+ }
+ };
+
+ FT_LOGD("cbhm_selection_get call");
+ ret = cbhm_selection_get(cbhm_handle, selection_type, cbhm_selection_data_cb, data);
+ if (CBHM_ERROR_NONE != ret) {
+ FT_LOGD("cbhm_selection_get error");
+ // return error
+ data->result->Error(kUnknownClipboardError, "Failed to gather data.");
+ // release the data
+ cbhm_close_service (data->cbhm_handle);
+ delete data;
+ // unlock guard for further processing
+ std::lock_guard lock(is_processing_mutex);
+ is_processing = false;
+ return;
+ }
} else if (method == "Clipboard.setData") {
result->NotImplemented();
} else if (method == "Clipboard.hasStrings") {