Skip to content

Commit 0435387

Browse files
committed
[Clipboard] getData implementation added
[Before] Clipboard.getData feature was not implemented [After] Dart code below is able to gather system clipboard data: Future<ClipboardData?> 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
1 parent e629333 commit 0435387

File tree

2 files changed

+108
-2
lines changed

2 files changed

+108
-2
lines changed

shell/platform/tizen/BUILD.gn

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ source_set("flutter_tizen") {
8787
"$custom_sysroot/usr/include/eo-1",
8888
"$custom_sysroot/usr/include/evas-1",
8989
"$custom_sysroot/usr/include/system",
90-
"$custom_sysroot/usr/include/wayland-extension"
90+
"$custom_sysroot/usr/include/wayland-extension",
91+
"$custom_sysroot/usr/include/cbhm",
9192
]
9293

9394
lib_dirs = [ root_out_dir, "$custom_sysroot/usr/lib" ]
@@ -114,6 +115,7 @@ source_set("flutter_tizen") {
114115
"tbm",
115116
"tdm-client",
116117
"wayland-client",
118+
"cbhm",
117119
]
118120

119121
if (tizen_sdk_4) {

shell/platform/tizen/channels/platform_channel.cc

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,25 @@
44

55
#include "platform_channel.h"
66

7+
#include <mutex>
78
#include <app.h>
9+
#include <cbhm.h>
810

911
#include "flutter/shell/platform/common/cpp/json_method_codec.h"
1012
#include "flutter/shell/platform/tizen/tizen_log.h"
1113

1214
static constexpr char kChannelName[] = "flutter/platform";
1315

16+
// Clipboard.getData constants and variables
17+
std::mutex is_processing_mutex;
18+
static bool is_processing = false;
19+
static constexpr char kTextKey[] = "text";
20+
static constexpr char kTextPlainFormat[] = "text/plain";
21+
static constexpr char kUnknownClipboardFormatError[] =
22+
"Unknown clipboard format error";
23+
static constexpr char kUnknownClipboardError[] =
24+
"Unknown error during clipboard data retrieval";
25+
1426
PlatformChannel::PlatformChannel(flutter::BinaryMessenger* messenger)
1527
: channel_(std::make_unique<flutter::MethodChannel<rapidjson::Document>>(
1628
messenger, kChannelName, &flutter::JsonMethodCodec::GetInstance())) {
@@ -37,7 +49,99 @@ void PlatformChannel::HandleMethodCall(
3749
} else if (method == "HapticFeedback.vibrate") {
3850
result->NotImplemented();
3951
} else if (method == "Clipboard.getData") {
40-
result->NotImplemented();
52+
const rapidjson::Value& format = call.arguments()[0];
53+
54+
// https://api.flutter.dev/flutter/services/Clipboard/kTextPlain-constant.html
55+
// API supports only kTextPlain format, however cbhm API supports also other formats
56+
if (strcmp(format.GetString(), kTextPlainFormat) != 0) {
57+
result->Error(kUnknownClipboardFormatError,
58+
"Clipboard API only supports text.");
59+
return;
60+
}
61+
62+
// Report error on next calls until current will be finished.
63+
// Native API - cbhm_selection_get works on static struct, so accessing clipboard parallelly will end
64+
// with race regarding returning values - cbhm_selection_data_cb will be triggered only for latest call.
65+
// TODO consider some queuing mechnism instead of returning error for next calls
66+
{
67+
std::lock_guard<std::mutex> lock(is_processing_mutex);
68+
if (is_processing) {
69+
result->Error(kUnknownClipboardError, "Already processing by other thread.");
70+
return;
71+
}
72+
is_processing = true;
73+
}
74+
75+
cbhm_sel_type_e selection_type = CBHM_SEL_TYPE_TEXT;
76+
77+
cbhm_h cbhm_handle = nullptr;
78+
int ret = cbhm_open_service (&cbhm_handle);
79+
if (CBHM_ERROR_NONE != ret) {
80+
result->Error(kUnknownClipboardError, "Failed to initialize cbhm service.");
81+
return;
82+
}
83+
84+
// additional check if data in clipboard
85+
ret = cbhm_item_count_get(cbhm_handle);
86+
if (ret <= 0) {
87+
result->Error(kUnknownClipboardError, "No clipboard data available.");
88+
// release the data
89+
cbhm_close_service (cbhm_handle);
90+
// unlock guard for further processing
91+
std::lock_guard<std::mutex> lock(is_processing_mutex);
92+
is_processing = false;
93+
return;
94+
}
95+
96+
struct method_data_t {
97+
std::unique_ptr<flutter::MethodResult<rapidjson::Document>> result;
98+
cbhm_h cbhm_handle;
99+
};
100+
// invalidates the result pointer
101+
method_data_t* data = new method_data_t{};
102+
data->result = std::move(result);
103+
data->cbhm_handle = cbhm_handle;
104+
105+
auto cbhm_selection_data_cb = [](cbhm_h cbhm_handle, const char *buf, size_t len, void *user_data) -> int {
106+
auto data = static_cast<method_data_t*>(user_data);
107+
// move unique_ptr from method_data_t and then release memory
108+
auto result = std::move(data->result);
109+
cbhm_close_service (data->cbhm_handle);
110+
delete data;
111+
112+
FT_LOGD("cbhm_selection_get SUCCESS (%d) %s", len, buf);
113+
{
114+
std::lock_guard<std::mutex> lock(is_processing_mutex);
115+
is_processing = false;
116+
}
117+
if (buf) {
118+
rapidjson::Document document;
119+
document.SetObject();
120+
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
121+
document.AddMember(rapidjson::Value(kTextKey, allocator),
122+
rapidjson::Value(std::string{buf, len}, allocator), allocator);
123+
result->Success(document);
124+
return CBHM_ERROR_NONE;
125+
} else {
126+
result->Error(kUnknownClipboardError, "Data buffer is null.");
127+
return CBHM_ERROR_NO_DATA;
128+
}
129+
};
130+
131+
FT_LOGD("cbhm_selection_get call");
132+
ret = cbhm_selection_get(cbhm_handle, selection_type, cbhm_selection_data_cb, data);
133+
if (CBHM_ERROR_NONE != ret) {
134+
FT_LOGD("cbhm_selection_get error");
135+
// return error
136+
data->result->Error(kUnknownClipboardError, "Failed to gather data.");
137+
// release the data
138+
cbhm_close_service (data->cbhm_handle);
139+
delete data;
140+
// unlock guard for further processing
141+
std::lock_guard<std::mutex> lock(is_processing_mutex);
142+
is_processing = false;
143+
return;
144+
}
41145
} else if (method == "Clipboard.setData") {
42146
result->NotImplemented();
43147
} else if (method == "Clipboard.hasStrings") {

0 commit comments

Comments
 (0)