Skip to content

Commit f57e59a

Browse files
authored
Improve the clipboard implementation (#12)
1 parent c71260b commit f57e59a

File tree

5 files changed

+110
-17
lines changed

5 files changed

+110
-17
lines changed

flutter/shell/platform/tizen/BUILD.gn

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ config("flutter_tizen_config") {
1313
include_dirs = [
1414
"${sysroot_path}/usr/include/appfw",
1515
"${sysroot_path}/usr/include/base",
16+
"${sysroot_path}/usr/include/cbhm",
1617
"${sysroot_path}/usr/include/dali",
1718
"${sysroot_path}/usr/include/dali-adaptor",
1819
"${sysroot_path}/usr/include/dali-toolkit",
@@ -165,6 +166,11 @@ template("embedder") {
165166
]
166167
}
167168

169+
if (target_name == "flutter_tizen_mobile" ||
170+
target_name == "flutter_tizen_common") {
171+
libs += [ "cbhm" ]
172+
}
173+
168174
defines += invoker.defines
169175
defines += [ "FLUTTER_ENGINE_NO_PROTOTYPES" ]
170176

flutter/shell/platform/tizen/channels/app_control.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ AppControlResult AppControl::SendLaunchRequest() {
323323

324324
AppControlResult AppControl::SendLaunchRequestWithReply(
325325
ReplyCallback on_reply) {
326+
on_reply_ = std::move(on_reply);
327+
326328
auto reply_callback = [](app_control_h request, app_control_h reply,
327329
app_control_result_e result, void* user_data) {
328330
auto* app_control = static_cast<AppControl*>(user_data);
@@ -342,7 +344,6 @@ AppControlResult AppControl::SendLaunchRequestWithReply(
342344
app_control->on_reply_(EncodableValue(map));
343345
app_control->on_reply_ = nullptr;
344346
};
345-
on_reply_ = on_reply;
346347
return app_control_send_launch_request(handle_, reply_callback, this);
347348
}
348349

flutter/shell/platform/tizen/channels/platform_channel.cc

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ constexpr char kPortraitDown[] = "DeviceOrientation.portraitDown";
5757
constexpr char kLandscapeLeft[] = "DeviceOrientation.landscapeLeft";
5858
constexpr char kLandscapeRight[] = "DeviceOrientation.landscapeRight";
5959

60-
// Naive implementation using std::string as a container of internal clipboard
61-
// data.
62-
std::string text_clipboard = "";
63-
6460
} // namespace
6561

6662
PlatformChannel::PlatformChannel(BinaryMessenger* messenger,
@@ -70,14 +66,25 @@ PlatformChannel::PlatformChannel(BinaryMessenger* messenger,
7066
kChannelName,
7167
&JsonMethodCodec::GetInstance())),
7268
view_(view) {
69+
#if defined(MOBILE_PROFILE) || defined(COMMON_PROFILE)
70+
int ret = cbhm_open_service(&cbhm_handle_);
71+
if (ret != CBHM_ERROR_NONE) {
72+
FT_LOG(Error) << "Failed to initialize the clipboard service.";
73+
}
74+
#endif
75+
7376
channel_->SetMethodCallHandler(
7477
[this](const MethodCall<rapidjson::Document>& call,
7578
std::unique_ptr<MethodResult<rapidjson::Document>> result) {
7679
HandleMethodCall(call, std::move(result));
7780
});
7881
}
7982

80-
PlatformChannel::~PlatformChannel() {}
83+
PlatformChannel::~PlatformChannel() {
84+
#if defined(MOBILE_PROFILE) || defined(COMMON_PROFILE)
85+
cbhm_close_service(cbhm_handle_);
86+
#endif
87+
}
8188

8289
void PlatformChannel::HandleMethodCall(
8390
const MethodCall<rapidjson::Document>& method_call,
@@ -100,33 +107,36 @@ void PlatformChannel::HandleMethodCall(
100107
result->Success();
101108
} else if (method == kGetClipboardDataMethod) {
102109
// https://api.flutter.dev/flutter/services/Clipboard/kTextPlain-constant.html
103-
// The API supports only kTextPlain format.
110+
// The API only supports the plain text format.
104111
if (strcmp(arguments[0].GetString(), kTextPlainFormat) != 0) {
105112
result->Error(kUnknownClipboardFormatError,
106113
"Clipboard API only supports text.");
107114
return;
108115
}
109-
rapidjson::Document document;
110-
document.SetObject();
111-
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
112-
document.AddMember(rapidjson::Value(kTextKey, allocator),
113-
rapidjson::Value(text_clipboard, allocator), allocator);
114-
result->Success(document);
116+
GetClipboardData([result = result.release()](const std::string& data) {
117+
rapidjson::Document document;
118+
document.SetObject();
119+
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
120+
document.AddMember(rapidjson::Value(kTextKey, allocator),
121+
rapidjson::Value(data, allocator), allocator);
122+
result->Success(document);
123+
delete result;
124+
});
115125
} else if (method == kSetClipboardDataMethod) {
116126
const rapidjson::Value& document = *arguments;
117127
auto iter = document.FindMember(kTextKey);
118128
if (iter == document.MemberEnd()) {
119129
result->Error(kUnknownClipboardError, "Invalid message format.");
120130
return;
121131
}
122-
text_clipboard = iter->value.GetString();
132+
SetClipboardData(iter->value.GetString());
123133
result->Success();
124134
} else if (method == kClipboardHasStringsMethod) {
125135
rapidjson::Document document;
126136
document.SetObject();
127137
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
128138
document.AddMember(rapidjson::Value(kValueKey, allocator),
129-
rapidjson::Value(!text_clipboard.empty()), allocator);
139+
rapidjson::Value(ClipboardHasStrings()), allocator);
130140
result->Success(document);
131141
} else if (method == kRestoreSystemUiOverlaysMethod) {
132142
RestoreSystemUiOverlays();
@@ -177,6 +187,59 @@ void PlatformChannel::HapticFeedbackVibrate(const std::string& feedback_type) {
177187
FeedbackManager::GetInstance().Vibrate();
178188
}
179189

190+
void PlatformChannel::GetClipboardData(ClipboardCallback on_data) {
191+
on_clipboard_data_ = std::move(on_data);
192+
193+
#if defined(MOBILE_PROFILE) || defined(COMMON_PROFILE)
194+
int ret = cbhm_selection_get(
195+
cbhm_handle_, CBHM_SEL_TYPE_TEXT,
196+
[](cbhm_h cbhm_handle, const char* buf, size_t len,
197+
void* user_data) -> int {
198+
auto* self = static_cast<PlatformChannel*>(user_data);
199+
std::string data;
200+
if (buf) {
201+
data = std::string(buf, len);
202+
}
203+
self->on_clipboard_data_(data);
204+
self->on_clipboard_data_ = nullptr;
205+
return CBHM_ERROR_NONE;
206+
},
207+
this);
208+
if (ret != CBHM_ERROR_NONE) {
209+
if (ret == CBHM_ERROR_NO_DATA) {
210+
FT_LOG(Info) << "No clipboard data available.";
211+
} else {
212+
FT_LOG(Error) << "Failed to get clipboard data.";
213+
}
214+
on_clipboard_data_("");
215+
on_clipboard_data_ = nullptr;
216+
}
217+
#else
218+
on_clipboard_data_(clipboard_);
219+
on_clipboard_data_ = nullptr;
220+
#endif
221+
}
222+
223+
void PlatformChannel::SetClipboardData(const std::string& data) {
224+
#if defined(MOBILE_PROFILE) || defined(COMMON_PROFILE)
225+
int ret = cbhm_selection_set(cbhm_handle_, CBHM_SEL_TYPE_TEXT, data.c_str(),
226+
data.length());
227+
if (ret != CBHM_ERROR_NONE) {
228+
FT_LOG(Error) << "Failed to set clipboard data.";
229+
}
230+
#else
231+
clipboard_ = data;
232+
#endif
233+
}
234+
235+
bool PlatformChannel::ClipboardHasStrings() {
236+
#if defined(MOBILE_PROFILE) || defined(COMMON_PROFILE)
237+
return cbhm_item_count_get(cbhm_handle_) > 0;
238+
#else
239+
return !clipboard_.empty();
240+
#endif
241+
}
242+
180243
void PlatformChannel::RestoreSystemUiOverlays() {
181244
if (view_->GetType() != TizenViewType::kWindow) {
182245
return;

flutter/shell/platform/tizen/channels/platform_channel.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
#ifndef EMBEDDER_PLATFORM_CHANNEL_H_
66
#define EMBEDDER_PLATFORM_CHANNEL_H_
77

8+
#if defined(MOBILE_PROFILE) || defined(COMMON_PROFILE)
9+
#include <cbhm.h>
10+
#endif
11+
12+
#include <functional>
813
#include <memory>
914
#include <string>
1015
#include <vector>
@@ -22,21 +27,39 @@ class PlatformChannel {
2227
virtual ~PlatformChannel();
2328

2429
private:
30+
using ClipboardCallback = std::function<void(const std::string& data)>;
31+
2532
void HandleMethodCall(
2633
const MethodCall<rapidjson::Document>& call,
2734
std::unique_ptr<MethodResult<rapidjson::Document>> result);
2835

2936
void SystemNavigatorPop();
3037
void PlaySystemSound(const std::string& sound_type);
3138
void HapticFeedbackVibrate(const std::string& feedback_type);
39+
void GetClipboardData(ClipboardCallback on_data);
40+
void SetClipboardData(const std::string& data);
41+
bool ClipboardHasStrings();
3242
void RestoreSystemUiOverlays();
3343
void SetEnabledSystemUiOverlays(const std::vector<std::string>& overlays);
3444
void SetPreferredOrientations(const std::vector<std::string>& orientations);
3545

3646
std::unique_ptr<MethodChannel<rapidjson::Document>> channel_;
3747

3848
// A reference to the native view managed by FlutterTizenView.
39-
TizenViewBase* view_;
49+
TizenViewBase* view_ = nullptr;
50+
51+
#if defined(MOBILE_PROFILE) || defined(COMMON_PROFILE)
52+
// The clipboard history manager.
53+
cbhm_h cbhm_handle_ = nullptr;
54+
#else
55+
// A container that holds clipboard data during the engine lifetime.
56+
//
57+
// Only used by profiles that do not support the Tizen clipboard API
58+
// (wearable and TV).
59+
std::string clipboard_;
60+
#endif
61+
62+
ClipboardCallback on_clipboard_data_ = nullptr;
4063
};
4164

4265
} // namespace flutter

flutter/shell/platform/tizen/channels/window_channel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class WindowChannel {
2727
std::unique_ptr<MethodChannel<EncodableValue>> channel_;
2828

2929
// A reference to the native window managed by FlutterTizenView.
30-
TizenWindow* window_;
30+
TizenWindow* window_ = nullptr;
3131
};
3232

3333
} // namespace flutter

0 commit comments

Comments
 (0)