1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "adapter/ohos/capability/clipboard/clipboard_impl.h"
17
18 #include "adapter/ohos/osal/pixel_map_ohos.h"
19 #include "adapter/ohos/capability/html/html_to_span.h"
20 #include "base/log/event_report.h"
21
22 namespace OHOS::Ace {
23 #ifndef SYSTEM_CLIPBOARD_SUPPORTED
24 namespace {
25 std::string g_clipboard;
26 RefPtr<PixelMap> g_pixmap;
27 } // namespace
28 #endif
29
30 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
TransitionCopyOption(CopyOptions copyOption)31 MiscServices::ShareOption TransitionCopyOption(CopyOptions copyOption)
32 {
33 auto shareOption = MiscServices::ShareOption::InApp;
34 switch (copyOption) {
35 case CopyOptions::InApp:
36 shareOption = MiscServices::ShareOption::InApp;
37 break;
38 case CopyOptions::Local:
39 shareOption = MiscServices::ShareOption::LocalDevice;
40 break;
41 case CopyOptions::Distributed:
42 shareOption = MiscServices::ShareOption::CrossDevice;
43 break;
44 default:
45 break;
46 }
47 return shareOption;
48 }
49
50 const std::string SPAN_STRING_TAG = "openharmony.styled-string";
51 #endif
52
HasData(const std::function<void (bool hasData)> & callback)53 void ClipboardImpl::HasData(const std::function<void(bool hasData)>& callback)
54 {
55 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
56 bool hasData = false;
57 CHECK_NULL_VOID(taskExecutor_);
58 taskExecutor_->PostSyncTask(
59 [&hasData]() { hasData = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData(); },
60 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardHasData");
61 callback(hasData);
62 #endif
63 }
64
HasDataType(const std::function<void (bool hasData)> & callback,const std::vector<std::string> & mimeTypes)65 void ClipboardImpl::HasDataType(
66 const std::function<void(bool hasData)>& callback, const std::vector<std::string>& mimeTypes)
67 {
68 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
69 bool hasData = false;
70 CHECK_NULL_VOID(taskExecutor_);
71 taskExecutor_->PostSyncTask(
72 [&hasData, mimeTypes]() {
73 for (auto mimeType = mimeTypes.begin(); mimeType != mimeTypes.end(); ++mimeType) {
74 hasData = OHOS::MiscServices::PasteboardClient::GetInstance()->HasDataType(*mimeType);
75 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "Clipboard data mimeType %{public}s available ? %{public}d",
76 mimeType->c_str(), hasData);
77 if (hasData) {
78 break;
79 }
80 }
81 },
82 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardHasDataType");
83 callback(hasData);
84 #endif
85 }
86
SetData(const std::string & data,CopyOptions copyOption,bool isDragData)87 void ClipboardImpl::SetData(const std::string& data, CopyOptions copyOption, bool isDragData)
88 {
89 CHECK_NULL_VOID(taskExecutor_);
90 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
91 auto shareOption = TransitionCopyOption(copyOption);
92 taskExecutor_->PostTask(
93 [data, shareOption, isDragData]() {
94 auto pasteData = OHOS::MiscServices::PasteboardClient::GetInstance()->CreatePlainTextData(data);
95 CHECK_NULL_VOID(pasteData);
96 pasteData->SetShareOption(shareOption);
97 pasteData->SetDraggedDataFlag(isDragData);
98 OHOS::MiscServices::PasteboardClient::GetInstance()->SetPasteData(*pasteData);
99 },
100 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardSetDataWithCopyOption", PriorityType::IMMEDIATE);
101 #else
102 taskExecutor_->PostTask(
103 [data]() { g_clipboard = data; }, TaskExecutor::TaskType::UI, "ArkUIClipboardSetTextPasteData",
104 PriorityType::IMMEDIATE);
105 #endif
106 }
107
SetPixelMapData(const RefPtr<PixelMap> & pixmap,CopyOptions copyOption)108 void ClipboardImpl::SetPixelMapData(const RefPtr<PixelMap>& pixmap, CopyOptions copyOption)
109 {
110 CHECK_NULL_VOID(taskExecutor_);
111 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
112 auto shareOption = TransitionCopyOption(copyOption);
113 taskExecutor_->PostTask(
114 [pixmap, shareOption]() {
115 CHECK_NULL_VOID(pixmap);
116 auto pixmapOhos = AceType::DynamicCast<PixelMapOhos>(pixmap);
117 CHECK_NULL_VOID(pixmapOhos);
118 auto pasteData = OHOS::MiscServices::PasteboardClient::GetInstance()->CreatePixelMapData(
119 pixmapOhos->GetPixelMapSharedPtr());
120 CHECK_NULL_VOID(pasteData);
121 pasteData->SetShareOption(shareOption);
122 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "Set pixmap to system clipboard");
123 OHOS::MiscServices::PasteboardClient::GetInstance()->SetPasteData(*pasteData);
124 },
125 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardSetPixelMapWithCopyOption", PriorityType::IMMEDIATE);
126 #else
127 taskExecutor_->PostTask(
128 [pixmap]() { g_pixmap = pixmap; }, TaskExecutor::TaskType::UI, "ArkUIClipboardSetImagePasteData",
129 PriorityType::IMMEDIATE);
130 #endif
131 }
132
GetData(const std::function<void (const std::string &)> & callback,bool syncMode)133 void ClipboardImpl::GetData(const std::function<void(const std::string&)>& callback, bool syncMode)
134 {
135 CHECK_NULL_VOID(callback);
136 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
137 CHECK_NULL_VOID(taskExecutor_);
138 if (syncMode) {
139 GetDataSync(callback);
140 } else {
141 GetDataAsync(callback);
142 }
143 #else
144 if (syncMode) {
145 callback(g_clipboard);
146 return;
147 }
148 CHECK_NULL_VOID(taskExecutor_);
149 taskExecutor_->PostTask(
150 [callback, taskExecutor = WeakClaim(RawPtr(taskExecutor_)), textData = g_clipboard]() {
151 callback(textData);
152 },
153 TaskExecutor::TaskType::UI, "ArkUIClipboardTextDataCallback", PriorityType::IMMEDIATE);
154 #endif
155 }
156
GetPixelMapData(const std::function<void (const RefPtr<PixelMap> &)> & callback,bool syncMode)157 void ClipboardImpl::GetPixelMapData(const std::function<void(const RefPtr<PixelMap>&)>& callback, bool syncMode)
158 {
159 if (!taskExecutor_ || !callback) {
160 return;
161 }
162 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
163 if (syncMode) {
164 GetPixelMapDataSync(callback);
165 } else {
166 GetPixelMapDataAsync(callback);
167 }
168 #else
169 if (syncMode) {
170 callback(g_pixmap);
171 } else {
172 taskExecutor_->PostTask([callback, taskExecutor = WeakClaim(RawPtr(taskExecutor_)),
173 imageData = g_pixmap]() { callback(imageData); },
174 TaskExecutor::TaskType::UI, "ArkUIClipboardImageDataCallback", PriorityType::IMMEDIATE);
175 }
176 #endif
177 }
178
CreatePasteDataMix()179 RefPtr<PasteDataMix> ClipboardImpl::CreatePasteDataMix()
180 {
181 return AceType::MakeRefPtr<PasteDataImpl>();
182 }
183
AddMultiTypeRecord(const RefPtr<PasteDataMix> & pasteData,const RefPtr<MultiTypeRecordMix> & multiTypeRecord)184 void ClipboardImpl::AddMultiTypeRecord(
185 const RefPtr<PasteDataMix>& pasteData, const RefPtr<MultiTypeRecordMix>& multiTypeRecord)
186 {
187 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
188 CHECK_NULL_VOID(taskExecutor_);
189 auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
190 CHECK_NULL_VOID(peData);
191 auto multiTypeRecordImpl = AceType::DynamicCast<MultiTypeRecordImpl>(multiTypeRecord);
192 CHECK_NULL_VOID(multiTypeRecordImpl);
193
194 std::map<std::string, std::shared_ptr<OHOS::MiscServices::EntryValue>> multiTypeDataMap;
195 if (!multiTypeRecordImpl->GetPlainText().empty()) {
196 multiTypeDataMap[OHOS::MiscServices::MIMETYPE_TEXT_PLAIN] =
197 std::make_shared<OHOS::MiscServices::EntryValue>(multiTypeRecordImpl->GetPlainText());
198 }
199 if (!multiTypeRecordImpl->GetUri().empty()) {
200 multiTypeDataMap[OHOS::MiscServices::MIMETYPE_TEXT_URI] =
201 std::make_shared<OHOS::MiscServices::EntryValue>(multiTypeRecordImpl->GetUri());
202 }
203 if (multiTypeRecordImpl->GetPixelMap()) {
204 multiTypeDataMap[OHOS::MiscServices::MIMETYPE_PIXELMAP] =
205 std::make_shared<OHOS::MiscServices::EntryValue>(multiTypeRecordImpl->GetPixelMap());
206 }
207 if (!multiTypeRecordImpl->GetSpanStringBuffer().empty()) {
208 multiTypeDataMap[SPAN_STRING_TAG] =
209 std::make_shared<OHOS::MiscServices::EntryValue>(multiTypeRecordImpl->GetSpanStringBuffer());
210 }
211
212 auto entry =
213 std::make_shared<std::map<std::string, std::shared_ptr<OHOS::MiscServices::EntryValue>>>(multiTypeDataMap);
214 peData->GetPasteDataData()->AddRecord(
215 MiscServices::PasteDataRecord::NewMultiTypeRecord(entry, GetMimeType(multiTypeDataMap)));
216 #endif
217 }
218
219 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
GetMimeType(std::map<std::string,std::shared_ptr<OHOS::MiscServices::EntryValue>> multiTypeDataMap)220 const std::string ClipboardImpl::GetMimeType(
221 std::map<std::string, std::shared_ptr<OHOS::MiscServices::EntryValue>> multiTypeDataMap)
222 {
223 std::string mimeType;
224 if (multiTypeDataMap.find(SPAN_STRING_TAG) != multiTypeDataMap.end()) {
225 mimeType = SPAN_STRING_TAG;
226 }
227 if (multiTypeDataMap.find(OHOS::MiscServices::MIMETYPE_PIXELMAP) != multiTypeDataMap.end()) {
228 mimeType = OHOS::MiscServices::MIMETYPE_PIXELMAP;
229 }
230 if (multiTypeDataMap.find(OHOS::MiscServices::MIMETYPE_TEXT_URI) != multiTypeDataMap.end()) {
231 mimeType = OHOS::MiscServices::MIMETYPE_TEXT_URI;
232 }
233 if (multiTypeDataMap.find(OHOS::MiscServices::MIMETYPE_TEXT_PLAIN) != multiTypeDataMap.end()) {
234 mimeType = OHOS::MiscServices::MIMETYPE_TEXT_PLAIN;
235 }
236 return mimeType;
237 }
238 #endif
239
SetPlainText(const std::string plainText)240 void MultiTypeRecordImpl::SetPlainText(const std::string plainText)
241 {
242 plainText_ = plainText;
243 }
SetUri(const std::string uri)244 void MultiTypeRecordImpl::SetUri(const std::string uri)
245 {
246 uri_ = uri;
247 }
SetPixelMap(RefPtr<PixelMap> pixelMap)248 void MultiTypeRecordImpl::SetPixelMap(RefPtr<PixelMap> pixelMap)
249 {
250 pixelMap_ = pixelMap;
251 }
GetPixelMap()252 const RefPtr<PixelMap> MultiTypeRecordImpl::GetPixelMap()
253 {
254 return pixelMap_;
255 }
GetPlainText()256 const std::string MultiTypeRecordImpl::GetPlainText()
257 {
258 return plainText_;
259 }
GetUri()260 const std::string MultiTypeRecordImpl::GetUri()
261 {
262 return uri_;
263 }
GetSpanStringBuffer()264 std::vector<uint8_t>& MultiTypeRecordImpl::GetSpanStringBuffer()
265 {
266 return spanStringBuffer_;
267 }
268
AddPixelMapRecord(const RefPtr<PasteDataMix> & pasteData,const RefPtr<PixelMap> & pixmap)269 void ClipboardImpl::AddPixelMapRecord(const RefPtr<PasteDataMix>& pasteData, const RefPtr<PixelMap>& pixmap)
270 {
271 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
272 CHECK_NULL_VOID(taskExecutor_);
273 auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
274 CHECK_NULL_VOID(peData);
275 auto pixmapOhos = AceType::DynamicCast<PixelMapOhos>(pixmap);
276 CHECK_NULL_VOID(pixmapOhos);
277 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add pixelMap record to pasteData");
278 peData->GetPasteDataData()->AddPixelMapRecord(pixmapOhos->GetPixelMapSharedPtr());
279 #endif
280 }
281
AddImageRecord(const RefPtr<PasteDataMix> & pasteData,const std::string & uri)282 void ClipboardImpl::AddImageRecord(const RefPtr<PasteDataMix>& pasteData, const std::string& uri)
283 {
284 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
285 CHECK_NULL_VOID(taskExecutor_);
286 auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
287 CHECK_NULL_VOID(peData);
288 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add url %{private}s record to pasteData", uri.c_str());
289 peData->GetPasteDataData()->AddUriRecord(OHOS::Uri(uri));
290 #endif
291 }
292
AddTextRecord(const RefPtr<PasteDataMix> & pasteData,const std::string & selectedStr)293 void ClipboardImpl::AddTextRecord(const RefPtr<PasteDataMix>& pasteData, const std::string& selectedStr)
294 {
295 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
296 CHECK_NULL_VOID(taskExecutor_);
297 auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
298 CHECK_NULL_VOID(peData);
299 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add text record to pasteData, length: %{public}d",
300 static_cast<int32_t>(StringUtils::ToWstring(selectedStr).length()));
301 peData->GetPasteDataData()->AddTextRecord(selectedStr);
302 #endif
303 }
304
AddSpanStringRecord(const RefPtr<PasteDataMix> & pasteData,std::vector<uint8_t> & data)305 void ClipboardImpl::AddSpanStringRecord(const RefPtr<PasteDataMix>& pasteData, std::vector<uint8_t>& data)
306 {
307 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
308 CHECK_NULL_VOID(taskExecutor_);
309 auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
310 CHECK_NULL_VOID(peData);
311 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add spanstring record to pasteData, length: %{public}d",
312 static_cast<int32_t>(data.size()));
313 peData->GetPasteDataData()->AddKvRecord(SPAN_STRING_TAG, data);
314 #endif
315 }
316
SetData(const RefPtr<PasteDataMix> & pasteData,CopyOptions copyOption)317 void ClipboardImpl::SetData(const RefPtr<PasteDataMix>& pasteData, CopyOptions copyOption)
318 {
319 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
320 auto shareOption = TransitionCopyOption(copyOption);
321 auto peData = AceType::DynamicCast<PasteDataImpl>(pasteData);
322 CHECK_NULL_VOID(peData);
323 taskExecutor_->PostTask(
324 [peData, shareOption]() {
325 auto pasteData = peData->GetPasteDataData();
326 pasteData->SetShareOption(shareOption);
327 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "add pasteData to clipboard, shareOption: %{public}d", shareOption);
328 OHOS::MiscServices::PasteboardClient::GetInstance()->SetPasteData(*pasteData);
329 },
330 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardSetMixDataWithCopyOption", PriorityType::IMMEDIATE);
331 #endif
332 }
333
GetData(const std::function<void (const std::string &,bool isLastRecord)> & textCallback,const std::function<void (const RefPtr<PixelMap> &,bool isLastRecord)> & pixelMapCallback,const std::function<void (const std::string &,bool isLastRecord)> & urlCallback,bool syncMode)334 void ClipboardImpl::GetData(const std::function<void(const std::string&, bool isLastRecord)>& textCallback,
335 const std::function<void(const RefPtr<PixelMap>&, bool isLastRecord)>& pixelMapCallback,
336 const std::function<void(const std::string&, bool isLastRecord)>& urlCallback, bool syncMode)
337 {
338 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
339 if (!taskExecutor_ || !textCallback || !pixelMapCallback || !urlCallback) {
340 return;
341 }
342
343 if (syncMode) {
344 GetDataSync(textCallback, pixelMapCallback, urlCallback);
345 } else {
346 GetDataAsync(textCallback, pixelMapCallback, urlCallback);
347 }
348 #endif
349 }
350
351 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
GetPasteDataData()352 std::shared_ptr<MiscServices::PasteData> PasteDataImpl::GetPasteDataData()
353 {
354 if (pasteData_ == nullptr) {
355 pasteData_ = std::make_shared<MiscServices::PasteData>();
356 }
357 return pasteData_;
358 }
SetUnifiedData(std::shared_ptr<MiscServices::PasteData> pasteData)359 void PasteDataImpl::SetUnifiedData(std::shared_ptr<MiscServices::PasteData> pasteData)
360 {
361 pasteData_ = pasteData;
362 }
363
GetDataSync(const std::function<void (const std::string &)> & callback)364 void ClipboardImpl::GetDataSync(const std::function<void(const std::string&)>& callback)
365 {
366 std::string result;
367 taskExecutor_->PostSyncTask(
368 [&result]() {
369 auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
370 CHECK_NULL_VOID(has);
371 OHOS::MiscServices::PasteData pasteData;
372 auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
373 CHECK_NULL_VOID(ok);
374 for (const auto& pasteDataRecord : pasteData.AllRecords()) {
375 if (pasteDataRecord == nullptr) {
376 continue;
377 }
378 if (pasteDataRecord->GetCustomData() != nullptr) {
379 auto customData = pasteDataRecord->GetCustomData();
380 auto itemData = customData->GetItemData();
381 if (itemData.find(SPAN_STRING_TAG) == itemData.end()) {
382 continue;
383 }
384 auto spanStr = SpanString::DecodeTlv(itemData[SPAN_STRING_TAG]);
385 if (spanStr) {
386 result = spanStr->GetString();
387 break;
388 }
389 }
390 if (pasteDataRecord->GetHtmlText() != nullptr) {
391 auto htmlText = pasteDataRecord->GetHtmlText();
392 HtmlToSpan toSpan;
393 auto spanStr = toSpan.ToSpanString(*htmlText, false);
394 if (spanStr) {
395 result = spanStr->GetString();
396 break;
397 }
398 }
399 }
400 if (result.empty()) {
401 auto textData = pasteData.GetPrimaryText();
402 CHECK_NULL_VOID(textData);
403 result = *textData;
404 }
405 },
406 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetTextDataSync");
407 callback(result);
408 }
409
GetDataAsync(const std::function<void (const std::string &)> & callback)410 void ClipboardImpl::GetDataAsync(const std::function<void(const std::string&)>& callback)
411 {
412 taskExecutor_->PostTask(
413 [callback, weakExecutor = WeakClaim(RawPtr(taskExecutor_)), weak = WeakClaim(this)]() {
414 auto clip = weak.Upgrade();
415 CHECK_NULL_VOID(clip);
416 auto taskExecutor = weakExecutor.Upgrade();
417 CHECK_NULL_VOID(taskExecutor);
418 if (!OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData()) {
419 EventReport::ReportClipboardFailEvent("SystemKeyboardData is not exist from MiscServices");
420 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "SystemKeyboardData is not exist from MiscServices");
421 taskExecutor->PostTask(
422 [callback]() { callback(""); }, TaskExecutor::TaskType::UI, "ArkUIClipboardHasDataFailed",
423 PriorityType::IMMEDIATE);
424 return;
425 }
426 OHOS::MiscServices::PasteData pasteData;
427 if (!OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData)) {
428 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardData fail from MiscServices");
429 taskExecutor->PostTask(
430 [callback]() { callback(""); }, TaskExecutor::TaskType::UI, "ArkUIClipboardGetDataFailed",
431 PriorityType::IMMEDIATE);
432 return;
433 }
434 std::string resText;
435 bool hasPlainRecord = false;
436 for (const auto& pasteDataRecord : pasteData.AllRecords()) {
437 clip->ProcessPasteDataRecord(pasteDataRecord, resText, hasPlainRecord);
438 }
439 if (resText.empty()) {
440 taskExecutor->PostTask(
441 [callback]() { callback(""); }, TaskExecutor::TaskType::UI, "ArkUIClipboardGetTextDataFailed",
442 PriorityType::IMMEDIATE);
443 return;
444 }
445 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "resText len:%{public}d", static_cast<int32_t>(resText.length()));
446 auto result = resText;
447 taskExecutor->PostTask(
448 [callback, result]() { callback(result); },
449 TaskExecutor::TaskType::UI, "ArkUIClipboardGetTextDataCallback", PriorityType::IMMEDIATE);
450 },
451 TaskExecutor::TaskType::BACKGROUND, "ArkUIClipboardGetTextDataAsync", PriorityType::IMMEDIATE);
452 }
453
ProcessPasteDataRecord(const std::shared_ptr<MiscServices::PasteDataRecord> & pasteDataRecord,std::string & resText,bool & hasPlainRecord)454 void ClipboardImpl::ProcessPasteDataRecord(const std::shared_ptr<MiscServices::PasteDataRecord>& pasteDataRecord,
455 std::string& resText, bool& hasPlainRecord)
456 {
457 if (pasteDataRecord == nullptr) {
458 return;
459 }
460 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "mimeType:%{public}s", pasteDataRecord->GetMimeType().c_str());
461 if (pasteDataRecord->GetPlainText() != nullptr) {
462 auto textData = pasteDataRecord->GetPlainText();
463 if (!hasPlainRecord) {
464 resText = "";
465 }
466 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "ProcessPlainText, length:%{public}zu", textData->length());
467 resText.append(*textData);
468 hasPlainRecord = true;
469 }
470 if (hasPlainRecord) {
471 return;
472 }
473 if (pasteDataRecord->GetHtmlText() != nullptr) {
474 auto htmlText = pasteDataRecord->GetHtmlText();
475 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "ProcessHtmlText, length=%{public}zu", htmlText->length());
476 HtmlToSpan toSpan;
477 auto spanStr = toSpan.ToSpanString(*htmlText);
478 if (spanStr) {
479 resText = spanStr->GetString();
480 return;
481 }
482 }
483 if (pasteDataRecord->GetCustomData() != nullptr) {
484 auto itemData = pasteDataRecord->GetCustomData()->GetItemData();
485 if (itemData.find(SPAN_STRING_TAG) != itemData.end()) {
486 auto spanStr = SpanString::DecodeTlv(itemData[SPAN_STRING_TAG]);
487 if (spanStr) {
488 resText = spanStr->GetString();
489 return;
490 }
491 }
492 }
493 }
494
GetDataSync(const std::function<void (const std::string &,bool isLastRecord)> & textCallback,const std::function<void (const RefPtr<PixelMap> &,bool isLastRecord)> & pixelMapCallback,const std::function<void (const std::string &,bool isLastRecord)> & urlCallback)495 void ClipboardImpl::GetDataSync(const std::function<void(const std::string&, bool isLastRecord)>& textCallback,
496 const std::function<void(const RefPtr<PixelMap>&, bool isLastRecord)>& pixelMapCallback,
497 const std::function<void(const std::string&, bool isLastRecord)>& urlCallback)
498 {
499 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "get data from clipboard, sync");
500 OHOS::MiscServices::PasteData pasteData;
501 taskExecutor_->PostSyncTask(
502 [&pasteData]() {
503 auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
504 CHECK_NULL_VOID(has);
505 auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
506 CHECK_NULL_VOID(ok);
507 },
508 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetPasteDataSync");
509
510 auto count = pasteData.GetRecordCount();
511 size_t index = 0;
512 for (const auto& pasteDataRecord : pasteData.AllRecords()) {
513 index++;
514 if (pasteDataRecord == nullptr) {
515 continue;
516 }
517 bool isLastRecord = index == count;
518 if (pasteDataRecord->GetPlainText() != nullptr) {
519 auto textData = pasteDataRecord->GetPlainText();
520 auto result = *textData;
521 textCallback(result, isLastRecord);
522 } else if (pasteDataRecord->GetPixelMap() != nullptr) {
523 auto imageData = pasteDataRecord->GetPixelMap();
524 auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
525 pixelMapCallback(result, isLastRecord);
526 } else if (pasteDataRecord->GetUri() != nullptr) {
527 auto textData = pasteDataRecord->GetUri();
528 auto result = (*textData).ToString();
529 urlCallback(result, isLastRecord);
530 }
531 }
532 }
533
GetDataAsync(const std::function<void (const std::string &,bool isLastRecord)> & textCallback,const std::function<void (const RefPtr<PixelMap> &,bool isLastRecord)> & pixelMapCallback,const std::function<void (const std::string &,bool isLastRecord)> & urlCallback)534 void ClipboardImpl::GetDataAsync(const std::function<void(const std::string&, bool isLastRecord)>& textCallback,
535 const std::function<void(const RefPtr<PixelMap>&, bool isLastRecord)>& pixelMapCallback,
536 const std::function<void(const std::string&, bool isLastRecord)>& urlCallback)
537 {
538 TAG_LOGI(AceLogTag::ACE_CLIPBOARD, "get data from clipboard, async");
539 taskExecutor_->PostTask(
540 [textCallback, pixelMapCallback, urlCallback, weakExecutor = WeakClaim(RawPtr(taskExecutor_))]() {
541 auto taskExecutor = weakExecutor.Upgrade();
542 CHECK_NULL_VOID(taskExecutor);
543 auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
544 CHECK_NULL_VOID(has);
545 OHOS::MiscServices::PasteData pasteData;
546 auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
547 CHECK_NULL_VOID(ok);
548 auto count = pasteData.GetRecordCount();
549 size_t index = 0;
550 for (const auto& pasteDataRecord : pasteData.AllRecords()) {
551 index++;
552 if (pasteDataRecord == nullptr) {
553 continue;
554 }
555 bool isLastRecord = index == count;
556 if (pasteDataRecord->GetPlainText() != nullptr) {
557 auto textData = pasteDataRecord->GetPlainText();
558 auto result = *textData;
559 taskExecutor->PostTask(
560 [textCallback, result, isLastRecord]() { textCallback(result, isLastRecord); },
561 TaskExecutor::TaskType::UI, "ArkUIClipboardGetTextCallback", PriorityType::IMMEDIATE);
562 } else if (pasteDataRecord->GetPixelMap() != nullptr) {
563 auto imageData = pasteDataRecord->GetPixelMap();
564 auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
565 taskExecutor->PostTask(
566 [pixelMapCallback, result, isLastRecord]() { pixelMapCallback(result, isLastRecord); },
567 TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageCallback", PriorityType::IMMEDIATE);
568 } else if (pasteDataRecord->GetUri() != nullptr) {
569 auto textData = pasteDataRecord->GetUri();
570 auto result = (*textData).ToString();
571 taskExecutor->PostTask([urlCallback, result, isLastRecord]() { urlCallback(result, isLastRecord); },
572 TaskExecutor::TaskType::UI, "ArkUIClipboardGetUrlCallback", PriorityType::IMMEDIATE);
573 }
574 }
575 },
576 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetDataAsync", PriorityType::IMMEDIATE);
577 }
578
GetSpanStringData(const std::function<void (std::vector<std::vector<uint8_t>> &,const std::string &,bool &)> & callback,bool syncMode)579 void ClipboardImpl::GetSpanStringData(
580 const std::function<void(std::vector<std::vector<uint8_t>>&, const std::string&, bool&)>& callback, bool syncMode)
581 {
582 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
583 if (!taskExecutor_ || !callback) {
584 return;
585 }
586
587 GetSpanStringDataHelper(callback, syncMode);
588 #endif
589 }
590
GetSpanStringDataHelper(const std::function<void (std::vector<std::vector<uint8_t>> &,const std::string &,bool &)> & callback,bool syncMode)591 void ClipboardImpl::GetSpanStringDataHelper(
592 const std::function<void(std::vector<std::vector<uint8_t>>&, const std::string&, bool&)>& callback, bool syncMode)
593 {
594 auto task = [callback, weakExecutor = WeakClaim(RawPtr(taskExecutor_)), weak = WeakClaim(this)]() {
595 auto clip = weak.Upgrade();
596 CHECK_NULL_VOID(clip);
597 auto taskExecutor = weakExecutor.Upgrade();
598 CHECK_NULL_VOID(taskExecutor);
599 auto hasData = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
600 CHECK_NULL_VOID(hasData);
601 OHOS::MiscServices::PasteData pasteData;
602 auto getDataRes = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
603 CHECK_NULL_VOID(getDataRes);
604 std::vector<std::vector<uint8_t>> arrays;
605 std::string text;
606 bool isMultiTypeRecord = false;
607 clip->ProcessSpanStringData(arrays, pasteData, text, isMultiTypeRecord);
608 auto textData = pasteData.GetPrimaryText();
609 if (textData && text.empty()) {
610 text.append(*textData);
611 }
612 auto result = text;
613 taskExecutor->PostTask(
614 [callback, arrays, result, isMultiTypeRecord]() mutable { callback(arrays, result, isMultiTypeRecord); },
615 TaskExecutor::TaskType::UI, "ArkUIClipboardGetSpanStringDataCallback", PriorityType::IMMEDIATE);
616 };
617 if (syncMode) {
618 taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::BACKGROUND, "ArkUIClipboardGetSpanStringDataSync");
619 } else {
620 taskExecutor_->PostTask(task, TaskExecutor::TaskType::BACKGROUND, "ArkUIClipboardGetSpanStringDataAsync",
621 PriorityType::IMMEDIATE);
622 }
623 }
624
ProcessSpanStringData(std::vector<std::vector<uint8_t>> & arrays,const OHOS::MiscServices::PasteData & pasteData,std::string & text,bool & isMultiTypeRecord)625 void ClipboardImpl::ProcessSpanStringData(std::vector<std::vector<uint8_t>>& arrays,
626 const OHOS::MiscServices::PasteData& pasteData, std::string& text, bool& isMultiTypeRecord)
627 {
628 for (const auto& pasteDataRecord : pasteData.AllRecords()) {
629 if (pasteDataRecord == nullptr) {
630 continue;
631 }
632 #ifdef SYSTEM_CLIPBOARD_SUPPORTED
633 std::vector<std::string> types = { SPAN_STRING_TAG, OHOS::MiscServices::MIMETYPE_TEXT_URI,
634 OHOS::MiscServices::MIMETYPE_PIXELMAP, OHOS::MiscServices::MIMETYPE_TEXT_PLAIN,
635 OHOS::MiscServices::MIMETYPE_TEXT_HTML };
636 auto validTypes = pasteDataRecord->GetValidMimeTypes(types);
637 if (validTypes.size() > 1) {
638 isMultiTypeRecord = true;
639 }
640 #endif
641 auto hasSpanString = false;
642 auto entryPtr = pasteDataRecord->GetEntryByMimeType(SPAN_STRING_TAG);
643 if (entryPtr) {
644 // entryValue InstanceOf OHOS::MiscServices::EntryValue.
645 auto entryValue = entryPtr->GetValue();
646 auto spanStringBuffer = std::get_if<std::vector<uint8_t>>(&entryValue);
647 arrays.emplace_back(*spanStringBuffer);
648 hasSpanString = true;
649 }
650 if (pasteDataRecord->GetHtmlText() != nullptr && !hasSpanString) {
651 auto htmlText = pasteDataRecord->GetHtmlText();
652 HtmlToSpan toSpan;
653 auto spanStr = toSpan.ToSpanString(*htmlText);
654 if (spanStr) {
655 std::vector<uint8_t> arr;
656 spanStr->EncodeTlv(arr);
657 arrays.emplace_back(arr);
658 }
659 }
660 if (pasteDataRecord->GetPlainText() != nullptr) {
661 auto textData = pasteDataRecord->GetPlainText();
662 text.append(*textData);
663 }
664 }
665 }
666
GetPixelMapDataSync(const std::function<void (const RefPtr<PixelMap> &)> & callback)667 void ClipboardImpl::GetPixelMapDataSync(const std::function<void(const RefPtr<PixelMap>&)>& callback)
668 {
669 RefPtr<PixelMap> pixmap;
670 taskExecutor_->PostSyncTask(
671 [&pixmap]() {
672 auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
673 CHECK_NULL_VOID(has);
674 OHOS::MiscServices::PasteData pasteData;
675 auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
676 CHECK_NULL_VOID(ok);
677 auto imageData = pasteData.GetPrimaryPixelMap();
678 CHECK_NULL_VOID(imageData);
679 pixmap = AceType::MakeRefPtr<PixelMapOhos>(imageData);
680 },
681 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetImageDataSync");
682 callback(pixmap);
683 }
684
GetPixelMapDataAsync(const std::function<void (const RefPtr<PixelMap> &)> & callback)685 void ClipboardImpl::GetPixelMapDataAsync(const std::function<void(const RefPtr<PixelMap>&)>& callback)
686 {
687 taskExecutor_->PostTask(
688 [callback, weakExecutor = WeakClaim(RawPtr(taskExecutor_))]() {
689 auto taskExecutor = weakExecutor.Upgrade();
690 CHECK_NULL_VOID(taskExecutor);
691 auto has = OHOS::MiscServices::PasteboardClient::GetInstance()->HasPasteData();
692 if (!has) {
693 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "SystemKeyboardData is not exist from MiscServices");
694 taskExecutor->PostTask(
695 [callback]() { callback(nullptr); }, TaskExecutor::TaskType::UI, "ArkUIClipboardHasDataFailed",
696 PriorityType::IMMEDIATE);
697 return;
698 }
699 OHOS::MiscServices::PasteData pasteData;
700 auto ok = OHOS::MiscServices::PasteboardClient::GetInstance()->GetPasteData(pasteData);
701 if (!ok) {
702 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardData fail from MiscServices");
703 taskExecutor->PostTask(
704 [callback]() { callback(nullptr); }, TaskExecutor::TaskType::UI, "ArkUIClipboardGetDataFailed",
705 PriorityType::IMMEDIATE);
706 return;
707 }
708 auto imageData = pasteData.GetPrimaryPixelMap();
709 if (!imageData) {
710 TAG_LOGW(AceLogTag::ACE_CLIPBOARD, "Get SystemKeyboardImageData fail from MiscServices");
711 taskExecutor->PostTask(
712 [callback]() { callback(nullptr); },
713 TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageDataFailed", PriorityType::IMMEDIATE);
714 return;
715 }
716 auto result = AceType::MakeRefPtr<PixelMapOhos>(imageData);
717 taskExecutor->PostTask(
718 [callback, result]() { callback(result); },
719 TaskExecutor::TaskType::UI, "ArkUIClipboardGetImageDataCallback", PriorityType::IMMEDIATE);
720 },
721 TaskExecutor::TaskType::PLATFORM, "ArkUIClipboardGetImageDataAsync", PriorityType::IMMEDIATE);
722 }
723 #endif
724
Clear()725 void ClipboardImpl::Clear() {}
726
727 } // namespace OHOS::Ace
728