1 /*
2 * Copyright (c) 2021-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 "frameworks/bridge/plugin_frontend/plugin_frontend_delegate.h"
17
18 #include <atomic>
19 #include <regex>
20 #include <string>
21
22 #include "base/log/ace_trace.h"
23 #include "base/log/event_report.h"
24 #include "base/resource/ace_res_config.h"
25 #include "base/thread/background_task_executor.h"
26 #include "base/utils/measure_util.h"
27 #include "base/utils/utils.h"
28 #include "core/common/ace_application_info.h"
29 #include "core/common/container.h"
30 #include "core/common/platform_bridge.h"
31 #include "core/common/thread_checker.h"
32 #include "core/components/dialog/dialog_component.h"
33 #include "core/components/toast/toast_component.h"
34 #include "frameworks/bridge/common/manifest/manifest_parser.h"
35 #include "frameworks/bridge/common/utils/utils.h"
36 #include "frameworks/bridge/js_frontend/js_ace_page.h"
37
38 namespace OHOS::Ace::Framework {
39 namespace {
40 constexpr uint8_t MIN_ROUT_COUNT = 2;
41 constexpr uint8_t JS_HEADER_OFFSET = 3;
42 constexpr int32_t INVALID_PAGE_ID = -1;
43 constexpr int32_t MAX_ROUTER_STACK = 32;
44 constexpr int32_t TOAST_TIME_MAX = 10000; // ms
45 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
46 constexpr int32_t MAX_PAGE_ID_SIZE = sizeof(uint64_t) * 8;
47 constexpr int32_t NANO_TO_MILLI = 1000000; // nanosecond to millisecond
48 constexpr int32_t TO_MILLI = 1000; // second to millisecond
49
50 const char MANIFEST_JSON[] = "manifest.json";
51 const char FILE_TYPE_JSON[] = ".json";
52 const char I18N_FOLDER[] = "i18n/";
53 const char RESOURCES_FOLDER[] = "resources/";
54 const char STYLES_FOLDER[] = "styles/";
55 const char I18N_FILE_SUFFIX[] = "/properties/string.json";
56 } // namespace
57
GenerateNextPageId()58 int32_t PluginFrontendDelegate::GenerateNextPageId()
59 {
60 for (int32_t idx = 0; idx < MAX_PAGE_ID_SIZE; ++idx) {
61 uint64_t bitMask = (1ULL << idx);
62 if ((bitMask & pageIdPool_.fetch_or(bitMask, std::memory_order_relaxed)) == 0) {
63 return idx;
64 }
65 }
66 return INVALID_PAGE_ID;
67 }
68
RecyclePageId(int32_t pageId)69 void PluginFrontendDelegate::RecyclePageId(int32_t pageId)
70 {
71 if (pageId < 0 || pageId >= MAX_PAGE_ID_SIZE) {
72 return;
73 }
74 uint64_t bitMask = (1ULL << pageId);
75 pageIdPool_.fetch_and(~bitMask, std::memory_order_relaxed);
76 }
77
PluginFrontendDelegate(const RefPtr<TaskExecutor> & taskExecutor,const LoadJsCallback & loadCallback,const JsMessageDispatcherSetterCallback & transferCallback,const EventCallback & asyncEventCallback,const EventCallback & syncEventCallback,const UpdatePageCallback & updatePageCallback,const ResetStagingPageCallback & resetLoadingPageCallback,const DestroyPageCallback & destroyPageCallback,const DestroyApplicationCallback & destroyApplicationCallback,const UpdateApplicationStateCallback & updateApplicationStateCallback,const TimerCallback & timerCallback,const MediaQueryCallback & mediaQueryCallback,const RequestAnimationCallback & requestAnimationCallback,const JsCallback & jsCallback,const OnWindowDisplayModeChangedCallBack & onWindowDisplayModeChangedCallBack,const OnConfigurationUpdatedCallBack & onConfigurationUpdatedCallBack,const OnSaveAbilityStateCallBack & onSaveAbilityStateCallBack,const OnRestoreAbilityStateCallBack & onRestoreAbilityStateCallBack,const OnNewWantCallBack & onNewWantCallBack,const OnActiveCallBack & onActiveCallBack,const OnInactiveCallBack & onInactiveCallBack,const OnMemoryLevelCallBack & onMemoryLevelCallBack,const OnStartContinuationCallBack & onStartContinuationCallBack,const OnCompleteContinuationCallBack & onCompleteContinuationCallBack,const OnRemoteTerminatedCallBack & onRemoteTerminatedCallBack,const OnSaveDataCallBack & onSaveDataCallBack,const OnRestoreDataCallBack & onRestoreDataCallBack)78 PluginFrontendDelegate::PluginFrontendDelegate(const RefPtr<TaskExecutor>& taskExecutor,
79 const LoadJsCallback& loadCallback, const JsMessageDispatcherSetterCallback& transferCallback,
80 const EventCallback& asyncEventCallback, const EventCallback& syncEventCallback,
81 const UpdatePageCallback& updatePageCallback, const ResetStagingPageCallback& resetLoadingPageCallback,
82 const DestroyPageCallback& destroyPageCallback, const DestroyApplicationCallback& destroyApplicationCallback,
83 const UpdateApplicationStateCallback& updateApplicationStateCallback,
84 const TimerCallback& timerCallback, const MediaQueryCallback& mediaQueryCallback,
85 const RequestAnimationCallback& requestAnimationCallback, const JsCallback& jsCallback,
86 const OnWindowDisplayModeChangedCallBack& onWindowDisplayModeChangedCallBack,
87 const OnConfigurationUpdatedCallBack& onConfigurationUpdatedCallBack,
88 const OnSaveAbilityStateCallBack& onSaveAbilityStateCallBack,
89 const OnRestoreAbilityStateCallBack& onRestoreAbilityStateCallBack,
90 const OnNewWantCallBack& onNewWantCallBack, const OnActiveCallBack& onActiveCallBack,
91 const OnInactiveCallBack& onInactiveCallBack, const OnMemoryLevelCallBack& onMemoryLevelCallBack,
92 const OnStartContinuationCallBack& onStartContinuationCallBack,
93 const OnCompleteContinuationCallBack& onCompleteContinuationCallBack,
94 const OnRemoteTerminatedCallBack& onRemoteTerminatedCallBack,
95 const OnSaveDataCallBack& onSaveDataCallBack,
96 const OnRestoreDataCallBack& onRestoreDataCallBack)
97 : loadJs_(loadCallback), dispatcherCallback_(transferCallback), asyncEvent_(asyncEventCallback),
98 syncEvent_(syncEventCallback), updatePage_(updatePageCallback), resetStagingPage_(resetLoadingPageCallback),
99 destroyPage_(destroyPageCallback), destroyApplication_(destroyApplicationCallback),
100 updateApplicationState_(updateApplicationStateCallback), timer_(timerCallback),
101 mediaQueryCallback_(mediaQueryCallback), requestAnimationCallback_(requestAnimationCallback),
102 jsCallback_(jsCallback), onWindowDisplayModeChanged_(onWindowDisplayModeChangedCallBack),
103 onConfigurationUpdated_(onConfigurationUpdatedCallBack),
104 onSaveAbilityState_(onSaveAbilityStateCallBack), onRestoreAbilityState_(onRestoreAbilityStateCallBack),
105 onNewWant_(onNewWantCallBack), onActive_(onActiveCallBack),
106 onInactive_(onInactiveCallBack), onMemoryLevel_(onMemoryLevelCallBack),
107 onStartContinuationCallBack_(onStartContinuationCallBack),
108 onCompleteContinuationCallBack_(onCompleteContinuationCallBack),
109 onRemoteTerminatedCallBack_(onRemoteTerminatedCallBack),
110 onSaveDataCallBack_(onSaveDataCallBack),
111 onRestoreDataCallBack_(onRestoreDataCallBack),
112 manifestParser_(AceType::MakeRefPtr<ManifestParser>()),
113 jsAccessibilityManager_(AccessibilityNodeManager::Create()),
114 mediaQueryInfo_(AceType::MakeRefPtr<MediaQueryInfo>()), taskExecutor_(taskExecutor)
115 {
116 }
117
~PluginFrontendDelegate()118 PluginFrontendDelegate::~PluginFrontendDelegate()
119 {
120 CHECK_RUN_ON(JS);
121 LOG_DESTROY();
122 }
123
GetMinPlatformVersion()124 int32_t PluginFrontendDelegate::GetMinPlatformVersion()
125 {
126 return manifestParser_->GetMinPlatformVersion();
127 }
128
RunPage(const std::string & url,const std::string & params)129 UIContentErrorCode PluginFrontendDelegate::RunPage(const std::string& url, const std::string& params)
130 {
131 ACE_SCOPED_TRACE("PluginFrontendDelegate::RunPage");
132 std::string jsonContent;
133 if (GetAssetContent(MANIFEST_JSON, jsonContent)) {
134 manifestParser_->Parse(jsonContent);
135 manifestParser_->Printer();
136 } else {
137 LOGE("RunPage parse manifest.json failed");
138 EventReport::SendPageRouterException(PageRouterExcepType::RUN_PAGE_ERR, url);
139 }
140
141 if (!url.empty()) {
142 mainPagePath_ = manifestParser_->GetRouter()->GetPagePath(url);
143 } else {
144 mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
145 }
146 return LoadPage(GenerateNextPageId(), PageTarget(mainPagePath_), false, params);
147 }
148
ChangeLocale(const std::string & language,const std::string & countryOrRegion)149 void PluginFrontendDelegate::ChangeLocale(const std::string& language, const std::string& countryOrRegion)
150 {
151 taskExecutor_->PostTask(
152 [language, countryOrRegion]() { AceApplicationInfo::GetInstance().ChangeLocale(language, countryOrRegion); },
153 TaskExecutor::TaskType::PLATFORM, "ArkUIPluginChangeLocale");
154 }
155
GetI18nData(std::unique_ptr<JsonValue> & json)156 void PluginFrontendDelegate::GetI18nData(std::unique_ptr<JsonValue>& json)
157 {
158 auto data = JsonUtil::CreateArray(true);
159 GetConfigurationCommon(I18N_FOLDER, data);
160 auto i18nData = JsonUtil::Create(true);
161 i18nData->Put("resources", data);
162 json->Put("i18n", i18nData);
163 }
164
GetResourceConfiguration(std::unique_ptr<JsonValue> & json)165 void PluginFrontendDelegate::GetResourceConfiguration(std::unique_ptr<JsonValue>& json)
166 {
167 auto data = JsonUtil::CreateArray(true);
168 GetConfigurationCommon(RESOURCES_FOLDER, data);
169 json->Put("resourcesConfiguration", data);
170 }
171
GetConfigurationCommon(const std::string & filePath,std::unique_ptr<JsonValue> & data)172 void PluginFrontendDelegate::GetConfigurationCommon(const std::string& filePath, std::unique_ptr<JsonValue>& data)
173 {
174 std::vector<std::string> files;
175 if (assetManager_) {
176 assetManager_->GetAssetList(filePath, files);
177 }
178
179 std::vector<std::string> fileNameList;
180 for (const auto& file : files) {
181 if (EndWith(file, FILE_TYPE_JSON) && !StartWith(file, STYLES_FOLDER)) {
182 fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
183 }
184 }
185
186 std::vector<std::string> priorityFileName;
187 if (filePath.compare(I18N_FOLDER) == 0) {
188 auto localeTag = AceApplicationInfo::GetInstance().GetLocaleTag();
189 priorityFileName = AceResConfig::GetLocaleFallback(localeTag, fileNameList);
190 } else {
191 priorityFileName = AceResConfig::GetResourceFallback(fileNameList);
192 }
193
194 for (const auto& fileName : priorityFileName) {
195 auto fileFullPath = filePath + fileName + std::string(FILE_TYPE_JSON);
196 std::string content;
197 if (GetAssetContent(fileFullPath, content)) {
198 auto fileData = ParseFileData(content);
199 if (fileData == nullptr) {
200 LOGW("parse %{private}s.json content failed", filePath.c_str());
201 } else {
202 data->Put(fileData);
203 }
204 }
205 }
206 }
207
LoadResourceConfiguration(std::map<std::string,std::string> & mediaResourceFileMap,std::unique_ptr<JsonValue> & currentResourceData)208 void PluginFrontendDelegate::LoadResourceConfiguration(std::map<std::string, std::string>& mediaResourceFileMap,
209 std::unique_ptr<JsonValue>& currentResourceData)
210 {
211 std::vector<std::string> files;
212 if (assetManager_) {
213 assetManager_->GetAssetList(RESOURCES_FOLDER, files);
214 }
215
216 std::set<std::string> resourceFolderName;
217 for (const auto& file : files) {
218 if (file.find_first_of("/") != std::string::npos) {
219 resourceFolderName.insert(file.substr(0, file.find_first_of("/")));
220 }
221 }
222
223 auto sortedResourceFolderPath = AceResConfig::GetDeclarativeResourceFallback(resourceFolderName);
224 for (const auto& folderName : sortedResourceFolderPath) {
225 auto fileFullPath = std::string(RESOURCES_FOLDER) + folderName + std::string(I18N_FILE_SUFFIX);
226 std::string content;
227 if (GetAssetContent(fileFullPath, content)) {
228 auto fileData = ParseFileData(content);
229 if (fileData != nullptr) {
230 currentResourceData->Put(fileData);
231 }
232 }
233 }
234
235 std::set<std::string> mediaFileName;
236 for (const auto& file : files) {
237 if (file.find_first_of("/") != std::string::npos) {
238 auto mediaPathName = file.substr(file.find_first_of("/"));
239 std::regex mediaPattern(R"(^\/media\/\w*(\.jpg|\.png|\.gif|\.svg|\.webp|\.bmp)$)");
240 std::smatch result;
241 if (std::regex_match(mediaPathName, result, mediaPattern)) {
242 mediaFileName.insert(mediaPathName.substr(mediaPathName.find_first_of("/")));
243 }
244 }
245 }
246
247 auto currentResTag = AceResConfig::GetCurrentDeviceResTag();
248 auto currentResolutionTag = currentResTag.substr(currentResTag.find_last_of("-") + 1);
249 for (auto folderName : sortedResourceFolderPath) {
250 for (auto fileName : mediaFileName) {
251 if (mediaResourceFileMap.find(fileName) == mediaResourceFileMap.end()) {
252 continue;
253 }
254 auto fullFileName = folderName + fileName;
255 if (std::find(files.begin(), files.end(), fullFileName) != files.end()) {
256 mediaResourceFileMap.emplace(fileName.substr(fileName.find_last_of("/") + 1),
257 std::string(RESOURCES_FOLDER).append(fullFileName));
258 }
259 }
260 if (mediaResourceFileMap.size() == mediaFileName.size()) {
261 break;
262 }
263 }
264 }
265
OnJSCallback(const std::string & callbackId,const std::string & data)266 void PluginFrontendDelegate::OnJSCallback(const std::string& callbackId, const std::string& data)
267 {
268 taskExecutor_->PostTask(
269 [weak = AceType::WeakClaim(this), callbackId, args = std::move(data)] {
270 auto delegate = weak.Upgrade();
271 if (delegate) {
272 delegate->jsCallback_(callbackId, args);
273 }
274 },
275 TaskExecutor::TaskType::JS, "ArkUIPluginHandleJsCallback");
276 }
277
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher) const278 void PluginFrontendDelegate::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) const
279 {
280 taskExecutor_->PostTask([dispatcherCallback = dispatcherCallback_, dispatcher] { dispatcherCallback(dispatcher); },
281 TaskExecutor::TaskType::JS, "ArkUIPluginSetJsMessageDispatcher");
282 }
283
TransferComponentResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data)284 void PluginFrontendDelegate::TransferComponentResponseData(int32_t callbackId, int32_t code,
285 std::vector<uint8_t>&& data)
286 {
287 auto pipelineContext = pipelineContextHolder_.Get();
288 WeakPtr<PipelineBase> contextWeak(pipelineContext);
289 taskExecutor_->PostTask(
290 [callbackId, data = std::move(data), contextWeak]() mutable {
291 auto context = contextWeak.Upgrade();
292 if (!context) {
293 LOGE("context is null");
294 } else if (!context->GetMessageBridge()) {
295 LOGE("messageBridge is null");
296 } else {
297 context->GetMessageBridge()->HandleCallback(callbackId, std::move(data));
298 }
299 },
300 TaskExecutor::TaskType::UI, "ArkUIPluginTransferComponentResponseData");
301 }
302
TransferJsResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const303 void PluginFrontendDelegate::TransferJsResponseData(
304 int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
305 {
306 if (groupJsBridge_ && groupJsBridge_->ForwardToWorker(callbackId)) {
307 groupJsBridge_->TriggerModuleJsCallback(callbackId, code, std::move(data));
308 return;
309 }
310
311 taskExecutor_->PostTask(
312 [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
313 if (groupJsBridge) {
314 groupJsBridge->TriggerModuleJsCallback(callbackId, code, std::move(data));
315 }
316 },
317 TaskExecutor::TaskType::JS, "ArkUIPluginTransferJsResponseData");
318 }
319
320 #if defined(PREVIEW)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const321 void PluginFrontendDelegate::TransferJsResponseDataPreview(
322 int32_t callbackId, int32_t code, ResponseData responseData) const
323 {
324 taskExecutor_->PostTask(
325 [callbackId, code, responseData, groupJsBridge = groupJsBridge_]() mutable {
326 if (groupJsBridge) {
327 groupJsBridge->TriggerModuleJsCallbackPreview(callbackId, code, responseData);
328 }
329 },
330 TaskExecutor::TaskType::JS, "ArkUIPluginTransferJsResponseData");
331 }
332 #endif
333
TransferJsPluginGetError(int32_t callbackId,int32_t errorCode,std::string && errorMessage) const334 void PluginFrontendDelegate::TransferJsPluginGetError(
335 int32_t callbackId, int32_t errorCode, std::string&& errorMessage) const
336 {
337 taskExecutor_->PostTask(
338 [callbackId, errorCode, errorMessage = std::move(errorMessage), groupJsBridge = groupJsBridge_]() mutable {
339 if (groupJsBridge) {
340 groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, errorCode, std::move(errorMessage));
341 }
342 },
343 TaskExecutor::TaskType::JS, "ArkUITransferJsPluginGetError");
344 }
345
TransferJsEventData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const346 void PluginFrontendDelegate::TransferJsEventData(int32_t callbackId, int32_t code,
347 std::vector<uint8_t>&& data) const
348 {
349 taskExecutor_->PostTask(
350 [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
351 if (groupJsBridge) {
352 groupJsBridge->TriggerEventJsCallback(callbackId, code, std::move(data));
353 }
354 },
355 TaskExecutor::TaskType::JS, "ArkUIPluginTransferJsEventData");
356 }
357
LoadPluginJsCode(std::string && jsCode) const358 void PluginFrontendDelegate::LoadPluginJsCode(std::string&& jsCode) const
359 {
360 taskExecutor_->PostTask(
361 [jsCode = std::move(jsCode), groupJsBridge = groupJsBridge_]() mutable {
362 if (groupJsBridge) {
363 groupJsBridge->LoadPluginJsCode(std::move(jsCode));
364 }
365 },
366 TaskExecutor::TaskType::JS, "ArkUILoadPluginJsCode");
367 }
368
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen) const369 void PluginFrontendDelegate::LoadPluginJsByteCode(
370 std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen) const
371 {
372 if (groupJsBridge_ == nullptr) {
373 LOGE("groupJsBridge_ is nullptr");
374 return;
375 }
376 taskExecutor_->PostTask(
377 [jsCode = std::move(jsCode), jsCodeLen = std::move(jsCodeLen), groupJsBridge = groupJsBridge_]() mutable {
378 groupJsBridge->LoadPluginJsByteCode(std::move(jsCode), std::move(jsCodeLen));
379 },
380 TaskExecutor::TaskType::JS, "ArkUILoadPluginJsByteCode");
381 }
382
OnPageBackPress()383 bool PluginFrontendDelegate::OnPageBackPress()
384 {
385 auto result = false;
386 taskExecutor_->PostSyncTask(
387 [weak = AceType::WeakClaim(this), &result] {
388 auto delegate = weak.Upgrade();
389 CHECK_NULL_VOID(delegate);
390 auto pageId = delegate->GetRunningPageId();
391 auto page = delegate->GetPage(pageId);
392 if (page) {
393 result = page->FireDeclarativeOnBackPressCallback();
394 }
395 },
396 TaskExecutor::TaskType::JS, "ArkUIPluginPageBackPress");
397 return result;
398 }
399
NotifyAppStorage(const WeakPtr<Framework::JsEngine> & jsEngineWeak,const std::string & key,const std::string & value)400 void PluginFrontendDelegate::NotifyAppStorage(const WeakPtr<Framework::JsEngine>& jsEngineWeak,
401 const std::string& key, const std::string& value)
402 {
403 taskExecutor_->PostTask(
404 [jsEngineWeak, key, value] {
405 auto jsEngine = jsEngineWeak.Upgrade();
406 CHECK_NULL_VOID(jsEngine);
407 jsEngine->NotifyAppStorage(key, value);
408 },
409 TaskExecutor::TaskType::JS, "ArkUIPluginNotifyAppStorage");
410 }
411
OnSuspended()412 void PluginFrontendDelegate::OnSuspended()
413 {
414 FireAsyncEvent("_root", std::string("\"viewsuspended\",null,null"), std::string(""));
415 }
416
OnBackGround()417 void PluginFrontendDelegate::OnBackGround()
418 {
419 taskExecutor_->PostTask(
420 [weak = AceType::WeakClaim(this)] {
421 auto delegate = weak.Upgrade();
422 CHECK_NULL_VOID(delegate);
423 delegate->OnPageHide();
424 },
425 TaskExecutor::TaskType::JS, "ArkUIPluginPageHide");
426 }
427
OnForeground()428 void PluginFrontendDelegate::OnForeground()
429 {
430 taskExecutor_->PostTask(
431 [weak = AceType::WeakClaim(this)] {
432 auto delegate = weak.Upgrade();
433 CHECK_NULL_VOID(delegate);
434 delegate->OnPageShow();
435 },
436 TaskExecutor::TaskType::JS, "ArkUIPluginPageShow");
437 }
438
OnConfigurationUpdated(const std::string & data)439 void PluginFrontendDelegate::OnConfigurationUpdated(const std::string& data)
440 {
441 taskExecutor_->PostSyncTask(
442 [onConfigurationUpdated = onConfigurationUpdated_, data] {
443 onConfigurationUpdated(data);
444 },
445 TaskExecutor::TaskType::JS, "ArkUIPluginConfigurationUpdated");
446 }
447
OnStartContinuation()448 bool PluginFrontendDelegate::OnStartContinuation()
449 {
450 bool ret = false;
451 taskExecutor_->PostSyncTask(
452 [weak = AceType::WeakClaim(this), &ret] {
453 auto delegate = weak.Upgrade();
454 if (delegate && delegate->onStartContinuationCallBack_) {
455 ret = delegate->onStartContinuationCallBack_();
456 }
457 },
458 TaskExecutor::TaskType::JS, "ArkUIPluginStartContinuation");
459 return ret;
460 }
461
OnCompleteContinuation(int32_t code)462 void PluginFrontendDelegate::OnCompleteContinuation(int32_t code)
463 {
464 taskExecutor_->PostSyncTask(
465 [weak = AceType::WeakClaim(this), code] {
466 auto delegate = weak.Upgrade();
467 if (delegate && delegate->onCompleteContinuationCallBack_) {
468 delegate->onCompleteContinuationCallBack_(code);
469 }
470 },
471 TaskExecutor::TaskType::JS, "ArkUIPluginCompleteContinuation");
472 }
473
OnRemoteTerminated()474 void PluginFrontendDelegate::OnRemoteTerminated()
475 {
476 taskExecutor_->PostSyncTask(
477 [weak = AceType::WeakClaim(this)] {
478 auto delegate = weak.Upgrade();
479 if (delegate && delegate->onRemoteTerminatedCallBack_) {
480 delegate->onRemoteTerminatedCallBack_();
481 }
482 },
483 TaskExecutor::TaskType::JS, "ArkUIPluginRemoteTerminated");
484 }
485
OnSaveData(std::string & data)486 void PluginFrontendDelegate::OnSaveData(std::string& data)
487 {
488 std::string savedData;
489 taskExecutor_->PostSyncTask(
490 [weak = AceType::WeakClaim(this), &savedData] {
491 auto delegate = weak.Upgrade();
492 if (delegate && delegate->onSaveDataCallBack_) {
493 delegate->onSaveDataCallBack_(savedData);
494 }
495 },
496 TaskExecutor::TaskType::JS, "ArkUIPluginSaveData");
497 std::string pageUri = GetRunningPageUrl();
498 data = std::string("{\"url\":\"").append(pageUri).append("\",\"__remoteData\":").append(savedData).append("}");
499 }
500
OnRestoreData(const std::string & data)501 bool PluginFrontendDelegate::OnRestoreData(const std::string& data)
502 {
503 bool ret = false;
504 taskExecutor_->PostSyncTask(
505 [weak = AceType::WeakClaim(this), &data, &ret] {
506 auto delegate = weak.Upgrade();
507 if (delegate && delegate->onRestoreDataCallBack_) {
508 ret = delegate->onRestoreDataCallBack_(data);
509 }
510 },
511 TaskExecutor::TaskType::JS, "ArkUIPluginRestoreData");
512 return ret;
513 }
514
OnMemoryLevel(const int32_t level)515 void PluginFrontendDelegate::OnMemoryLevel(const int32_t level)
516 {
517 taskExecutor_->PostTask(
518 [onMemoryLevel = onMemoryLevel_, level]() {
519 if (onMemoryLevel) {
520 onMemoryLevel(level);
521 }
522 },
523 TaskExecutor::TaskType::JS, "ArkUIPluginMemoryLevel");
524 }
525
GetPluginsUsed(std::string & data)526 void PluginFrontendDelegate::GetPluginsUsed(std::string& data)
527 {
528 if (!GetAssetContentImpl(assetManager_, "module_collection.txt", data)) {
529 LOGW("read failed, will load all the system plugin");
530 data = "All";
531 }
532 }
533
OnActive()534 void PluginFrontendDelegate::OnActive()
535 {
536 taskExecutor_->PostTask(
537 [onActive = onActive_]() {
538 onActive();
539 },
540 TaskExecutor::TaskType::JS, "ArkUIPluginActive");
541 }
542
OnInactive()543 void PluginFrontendDelegate::OnInactive()
544 {
545 taskExecutor_->PostTask(
546 [onInactive = onInactive_]() {
547 onInactive();
548 },
549 TaskExecutor::TaskType::JS, "ArkUIPluginInactive");
550 }
551
OnNewRequest(const std::string & data)552 void PluginFrontendDelegate::OnNewRequest(const std::string& data)
553 {
554 FireSyncEvent("_root", std::string("\"onNewRequest\","), data);
555 }
556
CallPopPage()557 void PluginFrontendDelegate::CallPopPage()
558 {
559 PopPage();
560 }
561
ResetStagingPage()562 void PluginFrontendDelegate::ResetStagingPage()
563 {
564 taskExecutor_->PostTask([resetStagingPage = resetStagingPage_] { resetStagingPage(); },
565 TaskExecutor::TaskType::JS, "ArkUIPluginResetStagingPage");
566 }
567
OnApplicationDestroy(const std::string & packageName)568 void PluginFrontendDelegate::OnApplicationDestroy(const std::string& packageName)
569 {
570 taskExecutor_->PostSyncTask(
571 [destroyApplication = destroyApplication_, packageName] { destroyApplication(packageName); },
572 TaskExecutor::TaskType::JS, "ArkUIPluginApplicationDestroy");
573 }
574
UpdateApplicationState(const std::string & packageName,Frontend::State state)575 void PluginFrontendDelegate::UpdateApplicationState(const std::string& packageName, Frontend::State state)
576 {
577 taskExecutor_->PostTask(
578 [updateApplicationState = updateApplicationState_, packageName, state] {
579 updateApplicationState(packageName, state);
580 },
581 TaskExecutor::TaskType::JS, "ArkUIPluginUpdateApplicationState");
582 }
583
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)584 void PluginFrontendDelegate::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
585 {
586 taskExecutor_->PostTask(
587 [onWindowDisplayModeChanged = onWindowDisplayModeChanged_, isShownInMultiWindow, data] {
588 onWindowDisplayModeChanged(isShownInMultiWindow, data);
589 },
590 TaskExecutor::TaskType::JS, "ArkUIPluginWindowDisplayModeChanged");
591 }
592
OnSaveAbilityState(std::string & data)593 void PluginFrontendDelegate::OnSaveAbilityState(std::string& data)
594 {
595 taskExecutor_->PostSyncTask(
596 [onSaveAbilityState = onSaveAbilityState_, &data] {
597 onSaveAbilityState(data);
598 },
599 TaskExecutor::TaskType::JS, "ArkUIPluginSaveAbilityState");
600 }
601
OnRestoreAbilityState(const std::string & data)602 void PluginFrontendDelegate::OnRestoreAbilityState(const std::string& data)
603 {
604 taskExecutor_->PostTask(
605 [onRestoreAbilityState = onRestoreAbilityState_, data] {
606 onRestoreAbilityState(data);
607 },
608 TaskExecutor::TaskType::JS, "ArkUIPluginRestoreAbilityState");
609 }
610
OnNewWant(const std::string & data)611 void PluginFrontendDelegate::OnNewWant(const std::string& data)
612 {
613 taskExecutor_->PostTask(
614 [onNewWant = onNewWant_, data] {
615 onNewWant(data);
616 },
617 TaskExecutor::TaskType::JS, "ArkUIPluginNewWant");
618 }
619
FireAsyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)620 void PluginFrontendDelegate::FireAsyncEvent(
621 const std::string& eventId, const std::string& param, const std::string& jsonArgs)
622 {
623 std::string args = param;
624 args.append(",null").append(",null"); // callback and dom changes
625 if (!jsonArgs.empty()) {
626 args.append(",").append(jsonArgs); // method args
627 }
628 taskExecutor_->PostTask(
629 [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
630 auto delegate = weak.Upgrade();
631 if (delegate) {
632 delegate->asyncEvent_(eventId, args);
633 }
634 },
635 TaskExecutor::TaskType::JS, "ArkUIPluginFireAsyncEvent");
636 }
637
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)638 bool PluginFrontendDelegate::FireSyncEvent(
639 const std::string& eventId, const std::string& param, const std::string& jsonArgs)
640 {
641 std::string resultStr;
642 FireSyncEvent(eventId, param, jsonArgs, resultStr);
643 return (resultStr == "true");
644 }
645
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs,std::string & result)646 void PluginFrontendDelegate::FireSyncEvent(
647 const std::string& eventId, const std::string& param, const std::string& jsonArgs, std::string& result)
648 {
649 int32_t callbackId = callbackCnt_++;
650 std::string args = param;
651 args.append("{\"_callbackId\":\"").append(std::to_string(callbackId)).append("\"}").append(",null");
652 if (!jsonArgs.empty()) {
653 args.append(",").append(jsonArgs); // method args
654 }
655 taskExecutor_->PostSyncTask(
656 [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
657 auto delegate = weak.Upgrade();
658 if (delegate) {
659 delegate->syncEvent_(eventId, args);
660 }
661 },
662 TaskExecutor::TaskType::JS, "ArkUIPluginFireSyncEvent");
663
664 result = jsCallBackResult_[callbackId];
665 jsCallBackResult_.erase(callbackId);
666 }
667
FireAccessibilityEvent(const AccessibilityEvent & accessibilityEvent)668 void PluginFrontendDelegate::FireAccessibilityEvent(const AccessibilityEvent& accessibilityEvent)
669 {
670 jsAccessibilityManager_->SendAccessibilityAsyncEvent(accessibilityEvent);
671 }
672
InitializeAccessibilityCallback()673 void PluginFrontendDelegate::InitializeAccessibilityCallback()
674 {
675 jsAccessibilityManager_->InitializeCallback();
676 }
677
678 // Start FrontendDelegate overrides.
Push(const std::string & uri,const std::string & params)679 void PluginFrontendDelegate::Push(const std::string& uri, const std::string& params)
680 {
681 Push(PageTarget(uri), params);
682 }
683
Replace(const std::string & uri,const std::string & params)684 void PluginFrontendDelegate::Replace(const std::string& uri, const std::string& params)
685 {
686 Replace(PageTarget(uri), params);
687 }
688
Back(const std::string & uri,const std::string & params)689 void PluginFrontendDelegate::Back(const std::string& uri, const std::string& params)
690 {
691 BackWithTarget(PageTarget(uri), params);
692 }
693
Push(const PageTarget & target,const std::string & params)694 void PluginFrontendDelegate::Push(const PageTarget& target, const std::string& params)
695 {
696 if (target.url.empty()) {
697 LOGE("router.Push uri is empty");
698 return;
699 }
700 if (isRouteStackFull_) {
701 LOGE("the router stack has reached its max size, you can't push any more pages.");
702 EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, target.url);
703 return;
704 }
705
706 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
707 if (!pagePath.empty()) {
708 LoadPage(GenerateNextPageId(), PageTarget(pagePath, target.container), false, params);
709 } else {
710 LOGW("[Engine Log] this uri not support in route push.");
711 }
712 }
713
Replace(const PageTarget & target,const std::string & params)714 void PluginFrontendDelegate::Replace(const PageTarget& target, const std::string& params)
715 {
716 if (target.url.empty()) {
717 LOGE("router.Replace uri is empty");
718 return;
719 }
720
721 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
722 if (!pagePath.empty()) {
723 LoadReplacePage(GenerateNextPageId(), PageTarget(pagePath, target.container), params);
724 } else {
725 LOGW("[Engine Log] this uri not support in route replace.");
726 }
727 }
728
PostponePageTransition()729 void PluginFrontendDelegate::PostponePageTransition()
730 {
731 taskExecutor_->PostTask(
732 [weak = AceType::WeakClaim(this)] {
733 auto delegate = weak.Upgrade();
734 CHECK_NULL_VOID(delegate);
735 auto pipelineContext = delegate->pipelineContextHolder_.Get();
736 pipelineContext->PostponePageTransition();
737 },
738 TaskExecutor::TaskType::UI, "ArkUIPluginPostponePageTransition");
739 }
740
LaunchPageTransition()741 void PluginFrontendDelegate::LaunchPageTransition()
742 {
743 taskExecutor_->PostTask(
744 [weak = AceType::WeakClaim(this)] {
745 auto delegate = weak.Upgrade();
746 CHECK_NULL_VOID(delegate);
747 auto pipelineContext = delegate->pipelineContextHolder_.Get();
748 pipelineContext->LaunchPageTransition();
749 },
750 TaskExecutor::TaskType::UI, "ArkUIPluginLaunchPageTransition");
751 }
752
BackWithTarget(const PageTarget & target,const std::string & params)753 void PluginFrontendDelegate::BackWithTarget(const PageTarget& target, const std::string& params)
754 {
755 if (target.url.empty()) {
756 {
757 std::lock_guard<std::mutex> lock(mutex_);
758 if (pageRouteStack_.size() > 1) {
759 pageId_ = pageRouteStack_[pageRouteStack_.size() - MIN_ROUT_COUNT].pageId;
760 }
761 if (!params.empty()) {
762 pageParamMap_[pageId_] = params;
763 }
764 }
765 PopPage();
766 } else {
767 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
768 if (!pagePath.empty()) {
769 pageId_ = GetPageIdByUrl(target.url);
770 if (!params.empty()) {
771 std::lock_guard<std::mutex> lock(mutex_);
772 pageParamMap_[pageId_] = params;
773 }
774 PopToPage(pagePath);
775 } else {
776 LOGW("[Engine Log] this uri not support in route Back.");
777 }
778 }
779 }
780
Clear()781 void PluginFrontendDelegate::Clear()
782 {
783 ClearInvisiblePages();
784 }
785
GetStackSize() const786 int32_t PluginFrontendDelegate::GetStackSize() const
787 {
788 std::lock_guard<std::mutex> lock(mutex_);
789 return static_cast<int32_t>(pageRouteStack_.size());
790 }
791
GetState(int32_t & index,std::string & name,std::string & path)792 void PluginFrontendDelegate::GetState(int32_t& index, std::string& name, std::string& path)
793 {
794 std::string url;
795 {
796 std::lock_guard<std::mutex> lock(mutex_);
797 if (pageRouteStack_.empty()) {
798 return;
799 }
800 index = static_cast<int32_t>(pageRouteStack_.size());
801 url = pageRouteStack_.back().url;
802 }
803 auto pos = url.rfind(".js");
804 if (pos == url.length() - JS_HEADER_OFFSET) {
805 url = url.substr(0, pos);
806 }
807 pos = url.rfind("/");
808 if (pos != std::string::npos) {
809 name = url.substr(pos + 1);
810 path = url.substr(0, pos + 1);
811 }
812 }
813
GetComponentsCount()814 size_t PluginFrontendDelegate::GetComponentsCount()
815 {
816 auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
817 CHECK_NULL_RETURN(pipelineContext, 0);
818 const auto& pageElement = pipelineContext->GetLastPage();
819 if (pageElement) {
820 return pageElement->GetComponentsCount();
821 }
822 return 0;
823 }
824
GetParams()825 std::string PluginFrontendDelegate::GetParams()
826 {
827 auto iter = pageParamMap_.find(pageId_);
828 if (iter != pageParamMap_.end()) {
829 return iter->second;
830 } else {
831 return "";
832 }
833 }
834
TriggerPageUpdate(int32_t pageId,bool directExecute)835 void PluginFrontendDelegate::TriggerPageUpdate(int32_t pageId, bool directExecute)
836 {
837 auto page = GetPage(pageId);
838 CHECK_NULL_VOID(page);
839
840 auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
841 ACE_DCHECK(jsPage);
842
843 // Pop all JS command and execute them in UI thread.
844 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
845 jsPage->PopAllCommands(*jsCommands);
846
847 auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
848 CHECK_NULL_VOID(pipelineContext);
849 WeakPtr<Framework::JsAcePage> jsPageWeak(jsPage);
850 WeakPtr<PipelineContext> contextWeak(pipelineContext);
851 auto updateTask = [jsPageWeak, contextWeak, jsCommands] {
852 ACE_SCOPED_TRACE("FlushUpdateCommands");
853 auto jsPage = jsPageWeak.Upgrade();
854 auto context = contextWeak.Upgrade();
855 if (!jsPage || !context) {
856 LOGE("Page update failed. page or context is null.");
857 EventReport::SendPageRouterException(PageRouterExcepType::UPDATE_PAGE_ERR);
858 return;
859 }
860 // Flush all JS commands.
861 for (const auto& command : *jsCommands) {
862 command->Execute(jsPage);
863 }
864 if (jsPage->GetDomDocument()) {
865 jsPage->GetDomDocument()->HandleComponentPostBinding();
866 }
867 auto accessibilityManager = context->GetAccessibilityManager();
868 if (accessibilityManager) {
869 accessibilityManager->HandleComponentPostBinding();
870 }
871
872 jsPage->ClearShowCommand();
873 std::vector<NodeId> dirtyNodes;
874 jsPage->PopAllDirtyNodes(dirtyNodes);
875 for (auto nodeId : dirtyNodes) {
876 auto patchComponent = jsPage->BuildPagePatch(nodeId);
877 if (patchComponent) {
878 context->ScheduleUpdate(patchComponent);
879 }
880 }
881 };
882
883 taskExecutor_->PostTask(
884 [updateTask, pipelineContext, directExecute]() {
885 pipelineContext->AddPageUpdateTask(std::move(updateTask), directExecute);
886 },
887 TaskExecutor::TaskType::UI, "ArkUIPluginAddPageUpdateTask");
888 }
889
PostJsTask(std::function<void ()> && task,const std::string & name)890 void PluginFrontendDelegate::PostJsTask(std::function<void()>&& task, const std::string& name)
891 {
892 taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS, name);
893 }
894
GetAppID() const895 const std::string& PluginFrontendDelegate::GetAppID() const
896 {
897 return manifestParser_->GetAppInfo()->GetAppID();
898 }
899
GetAppName() const900 const std::string& PluginFrontendDelegate::GetAppName() const
901 {
902 return manifestParser_->GetAppInfo()->GetAppName();
903 }
904
GetVersionName() const905 const std::string& PluginFrontendDelegate::GetVersionName() const
906 {
907 return manifestParser_->GetAppInfo()->GetVersionName();
908 }
909
GetVersionCode() const910 int32_t PluginFrontendDelegate::GetVersionCode() const
911 {
912 return manifestParser_->GetAppInfo()->GetVersionCode();
913 }
914
MeasureText(MeasureContext context)915 double PluginFrontendDelegate::MeasureText(MeasureContext context)
916 {
917 if (context.isFontSizeUseDefaultUnit && context.fontSize.has_value() &&
918 !AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
919 context.fontSize = Dimension(context.fontSize->Value(), DimensionUnit::VP);
920 }
921 return MeasureUtil::MeasureText(context);
922 }
923
MeasureTextSize(MeasureContext context)924 Size PluginFrontendDelegate::MeasureTextSize(MeasureContext context)
925 {
926 if (context.isFontSizeUseDefaultUnit && context.fontSize.has_value() &&
927 !AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
928 context.fontSize = Dimension(context.fontSize->Value(), DimensionUnit::VP);
929 }
930 return MeasureUtil::MeasureTextSize(context);
931 }
932
ShowToast(const NG::ToastInfo & toastInfo)933 void PluginFrontendDelegate::ShowToast(const NG::ToastInfo& toastInfo)
934 {
935 NG::ToastInfo updatedToastInfo = toastInfo;
936 updatedToastInfo.duration = std::clamp(toastInfo.duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
937 updatedToastInfo.isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
938 auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
939 taskExecutor_->PostTask(
940 [updatedToastInfo, context = pipelineContext] {
941 ToastComponent::GetInstance().Show(context, updatedToastInfo.message, updatedToastInfo.duration,
942 updatedToastInfo.bottom, updatedToastInfo.isRightToLeft);
943 },
944 TaskExecutor::TaskType::UI, "ArkUIPluginShowToast");
945 }
946
ShowDialog(const std::string & title,const std::string & message,const std::vector<ButtonInfo> & buttons,bool autoCancel,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)947 void PluginFrontendDelegate::ShowDialog(const std::string& title, const std::string& message,
948 const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
949 const std::set<std::string>& callbacks)
950 {
951 std::unordered_map<std::string, EventMarker> callbackMarkers;
952 if (callbacks.find(COMMON_SUCCESS) != callbacks.end()) {
953 auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
954 BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
955 successEventMarker, [callback, taskExecutor = taskExecutor_](int32_t successType) {
956 taskExecutor->PostTask(
957 [callback, successType]() { callback(0, successType); },
958 TaskExecutor::TaskType::JS, "ArkUIPluginShowDialogSuccess");
959 });
960 callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
961 }
962
963 if (callbacks.find(COMMON_CANCEL) != callbacks.end()) {
964 auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
965 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
966 cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
967 taskExecutor->PostTask(
968 [callback]() { callback(1, 0); }, TaskExecutor::TaskType::JS, "ArkUIPluginShowDialogCancel");
969 });
970 callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
971 }
972
973 if (callbacks.find(COMMON_COMPLETE) != callbacks.end()) {
974 auto completeEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
975 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
976 completeEventMarker, [callback, taskExecutor = taskExecutor_] {
977 taskExecutor->PostTask(
978 [callback]() { callback(MIN_ROUT_COUNT, 0); },
979 TaskExecutor::TaskType::JS, "ArkUIPluginShowDialogComplete");
980 });
981 callbackMarkers.emplace(COMMON_COMPLETE, completeEventMarker);
982 }
983
984 DialogProperties dialogProperties = {
985 .title = title,
986 .content = message,
987 .autoCancel = autoCancel,
988 .buttons = buttons,
989 .callbacks = std::move(callbackMarkers),
990 };
991 auto context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
992 if (context) {
993 context->ShowDialog(dialogProperties, AceApplicationInfo::GetInstance().IsRightToLeft());
994 }
995 }
996
GetBoundingRectData(NodeId nodeId)997 Rect PluginFrontendDelegate::GetBoundingRectData(NodeId nodeId)
998 {
999 Rect rect;
1000 auto task = [context = pipelineContextHolder_.Get(), nodeId, &rect]() {
1001 context->GetBoundingRectData(nodeId, rect);
1002 };
1003 PostSyncTaskToPage(task, "ArkUIPluginGetBoundingRectData");
1004 return rect;
1005 }
1006
GetInspector(NodeId nodeId)1007 std::string PluginFrontendDelegate::GetInspector(NodeId nodeId)
1008 {
1009 std::string attrs;
1010 auto task = [weak = WeakClaim(AceType::RawPtr(jsAccessibilityManager_)), nodeId, &attrs]() {
1011 auto accessibilityNodeManager = weak.Upgrade();
1012 if (accessibilityNodeManager) {
1013 attrs = accessibilityNodeManager->GetInspectorNodeById(nodeId);
1014 }
1015 };
1016 PostSyncTaskToPage(task, "ArkUIPluginGetInspectorNode");
1017 return attrs;
1018 }
1019
SetCallBackResult(const std::string & callBackId,const std::string & result)1020 void PluginFrontendDelegate::SetCallBackResult(const std::string& callBackId, const std::string& result)
1021 {
1022 jsCallBackResult_.try_emplace(StringToInt(callBackId), result);
1023 }
1024
WaitTimer(const std::string & callbackId,const std::string & delay,bool isInterval,bool isFirst)1025 void PluginFrontendDelegate::WaitTimer(
1026 const std::string& callbackId, const std::string& delay, bool isInterval, bool isFirst)
1027 {
1028 if (!isFirst) {
1029 auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1030 // If not find the callbackId in map, means this timer already was removed,
1031 // no need create a new cancelableTimer again.
1032 if (timeoutTaskIter == timeoutTaskMap_.end()) {
1033 return;
1034 }
1035 }
1036
1037 int32_t delayTime = StringToInt(delay);
1038 // CancelableCallback class can only be executed once.
1039 CancelableCallback<void()> cancelableTimer;
1040 cancelableTimer.Reset([callbackId, delay, isInterval, call = timer_] { call(callbackId, delay, isInterval); });
1041 auto result = timeoutTaskMap_.try_emplace(callbackId, cancelableTimer);
1042 if (!result.second) {
1043 result.first->second = cancelableTimer;
1044 }
1045 taskExecutor_->PostDelayedTask(cancelableTimer, TaskExecutor::TaskType::JS, delayTime, "ArkUIPluginWaitTimer");
1046 }
1047
ClearTimer(const std::string & callbackId)1048 void PluginFrontendDelegate::ClearTimer(const std::string& callbackId)
1049 {
1050 auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1051 if (timeoutTaskIter != timeoutTaskMap_.end()) {
1052 timeoutTaskIter->second.Cancel();
1053 timeoutTaskMap_.erase(timeoutTaskIter);
1054 } else {
1055 LOGW("ClearTimer callbackId not found");
1056 }
1057 }
1058
PostSyncTaskToPage(std::function<void ()> && task,const std::string & name)1059 void PluginFrontendDelegate::PostSyncTaskToPage(std::function<void()>&& task, const std::string& name)
1060 {
1061 pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
1062 taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::UI, name);
1063 }
1064
AddTaskObserver(std::function<void ()> && task)1065 void PluginFrontendDelegate::AddTaskObserver(std::function<void()>&& task)
1066 {
1067 taskExecutor_->AddTaskObserver(std::move(task));
1068 }
1069
RemoveTaskObserver()1070 void PluginFrontendDelegate::RemoveTaskObserver()
1071 {
1072 taskExecutor_->RemoveTaskObserver();
1073 }
1074
GetAssetContent(const std::string & url,std::string & content)1075 bool PluginFrontendDelegate::GetAssetContent(const std::string& url, std::string& content)
1076 {
1077 return GetAssetContentImpl(assetManager_, url, content);
1078 }
1079
GetAssetContent(const std::string & url,std::vector<uint8_t> & content)1080 bool PluginFrontendDelegate::GetAssetContent(const std::string& url, std::vector<uint8_t>& content)
1081 {
1082 return GetAssetContentImpl(assetManager_, url, content);
1083 }
1084
GetAssetPath(const std::string & url)1085 std::string PluginFrontendDelegate::GetAssetPath(const std::string& url)
1086 {
1087 return GetAssetPathImpl(assetManager_, url);
1088 }
1089
LoadPage(int32_t pageId,const PageTarget & target,bool isMainPage,const std::string & params)1090 UIContentErrorCode PluginFrontendDelegate::LoadPage(
1091 int32_t pageId, const PageTarget& target, bool isMainPage, const std::string& params)
1092 {
1093 {
1094 std::lock_guard<std::mutex> lock(mutex_);
1095 pageId_ = pageId;
1096 pageParamMap_[pageId] = params;
1097 }
1098 auto url = target.url;
1099 if (pageId == INVALID_PAGE_ID) {
1100 LOGE("PluginFrontendDelegate, invalid page id");
1101 EventReport::SendPageRouterException(PageRouterExcepType::LOAD_PAGE_ERR, url);
1102 return UIContentErrorCode::INVALID_PAGE_ID;
1103 }
1104 if (isStagingPageExist_) {
1105 LOGE("PluginFrontendDelegate, load page failed, waiting for current page loading finish.");
1106 RecyclePageId(pageId);
1107 return UIContentErrorCode::STAGING_PAGE_EXIST;
1108 }
1109 isStagingPageExist_ = true;
1110 auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1111 auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1112 page->SetPageParams(params);
1113 page->SetPluginComponentJsonData(params);
1114 page->SetFlushCallback([weak = AceType::WeakClaim(this), isMainPage](const RefPtr<JsAcePage>& acePage) {
1115 auto delegate = weak.Upgrade();
1116 if (delegate && acePage) {
1117 delegate->FlushPageCommand(acePage, acePage->GetUrl(), isMainPage);
1118 }
1119 });
1120 LoadJS(page, url, isMainPage);
1121 return UIContentErrorCode::NO_ERRORS;
1122 }
1123
LoadJS(const RefPtr<Framework::JsAcePage> & page,const std::string & url,bool isMainPage)1124 void PluginFrontendDelegate::LoadJS(
1125 const RefPtr<Framework::JsAcePage>& page, const std::string& url, bool isMainPage)
1126 {
1127 taskExecutor_->PostTask(
1128 [weak = AceType::WeakClaim(this), page, url, isMainPage] {
1129 auto delegate = weak.Upgrade();
1130 CHECK_NULL_VOID(delegate);
1131 delegate->loadJs_(url, page, isMainPage);
1132 page->FlushCommands();
1133 // just make sure the pipelineContext is created.
1134 auto pipeline = delegate->pipelineContextHolder_.Get();
1135 pipeline->SetMinPlatformVersion(delegate->GetMinPlatformVersion());
1136 delegate->taskExecutor_->PostTask(
1137 [weak, page] {
1138 auto delegate = weak.Upgrade();
1139 if (delegate && delegate->pipelineContextHolder_.Get()) {
1140 auto context = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1141 if (context) {
1142 context->FlushFocus();
1143 }
1144 }
1145 if (page->GetDomDocument()) {
1146 page->GetDomDocument()->HandlePageLoadFinish();
1147 }
1148 },
1149 TaskExecutor::TaskType::UI, "ArkUIPluginPageLoadFinish");
1150 },
1151 TaskExecutor::TaskType::JS, "ArkUIPluginLoadJsPage");
1152 }
1153
OnSurfaceChanged()1154 void PluginFrontendDelegate::OnSurfaceChanged()
1155 {
1156 if (mediaQueryInfo_->GetIsInit()) {
1157 mediaQueryInfo_->SetIsInit(false);
1158 }
1159 mediaQueryInfo_->EnsureListenerIdValid();
1160 OnMediaQueryUpdate();
1161 }
1162
OnMediaQueryUpdate(bool isSynchronous)1163 void PluginFrontendDelegate::OnMediaQueryUpdate(bool isSynchronous)
1164 {
1165 if (mediaQueryInfo_->GetIsInit()) {
1166 return;
1167 }
1168
1169 taskExecutor_->PostTask(
1170 [weak = AceType::WeakClaim(this)] {
1171 auto delegate = weak.Upgrade();
1172 CHECK_NULL_VOID(delegate);
1173 const auto& info = delegate->mediaQueryInfo_->GetMediaQueryInfo();
1174 // request css mediaquery
1175 std::string param("\"viewsizechanged\",");
1176 param.append(info);
1177 delegate->asyncEvent_("_root", param);
1178
1179 // request js mediaquery
1180 const auto& listenerId = delegate->mediaQueryInfo_->GetListenerId();
1181 delegate->mediaQueryCallback_(listenerId, info);
1182 delegate->mediaQueryInfo_->ResetListenerId();
1183 },
1184 TaskExecutor::TaskType::JS, "ArkUIPluginMediaQueryUpdate");
1185 }
1186
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1187 void PluginFrontendDelegate::OnPageReady(
1188 const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1189 {
1190 // Pop all JS command and execute them in UI thread.
1191 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1192 page->PopAllCommands(*jsCommands);
1193
1194 auto pipelineContext = pipelineContextHolder_.Get();
1195 page->SetPipelineContext(pipelineContext);
1196 taskExecutor_->PostTask(
1197 [weak = AceType::WeakClaim(this), page, url, jsCommands, isMainPage] {
1198 auto delegate = weak.Upgrade();
1199 CHECK_NULL_VOID(delegate);
1200 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1201 CHECK_NULL_VOID(pipelineContext);
1202 // Flush all JS commands.
1203 for (const auto& command : *jsCommands) {
1204 command->Execute(page);
1205 }
1206 // Just clear all dirty nodes.
1207 page->ClearAllDirtyNodes();
1208 if (page->GetDomDocument()) {
1209 page->GetDomDocument()->HandleComponentPostBinding();
1210 }
1211 if (pipelineContext->GetAccessibilityManager()) {
1212 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1213 }
1214 if (pipelineContext->CanPushPage()) {
1215 if (!isMainPage) {
1216 delegate->OnPageHide();
1217 }
1218 delegate->OnPrePageChange(page);
1219 pipelineContext->PushPage(page->BuildPage(url), page->GetStageElement());
1220 delegate->OnPushPageSuccess(page, url);
1221 delegate->SetCurrentPage(page->GetPageId());
1222 delegate->OnMediaQueryUpdate();
1223 } else {
1224 // This page has been loaded but become useless now, the corresponding js instance
1225 // must be destroyed to avoid memory leak.
1226 delegate->OnPageDestroy(page->GetPageId());
1227 delegate->ResetStagingPage();
1228 }
1229 delegate->isStagingPageExist_ = false;
1230 if (isMainPage) {
1231 delegate->OnPageShow();
1232 }
1233 },
1234 TaskExecutor::TaskType::UI, "ArkUIPluginPageReady");
1235 }
1236
OnPrePageChange(const RefPtr<JsAcePage> & page)1237 void PluginFrontendDelegate::OnPrePageChange(const RefPtr<JsAcePage>& page)
1238 {
1239 if (page && page->GetDomDocument() && jsAccessibilityManager_) {
1240 jsAccessibilityManager_->SetRootNodeId(page->GetDomDocument()->GetRootNodeId());
1241 }
1242 }
1243
FlushPageCommand(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1244 void PluginFrontendDelegate::FlushPageCommand(
1245 const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1246 {
1247 CHECK_NULL_VOID(page);
1248 if (page->FragmentCount() == 1) {
1249 OnPageReady(page, url, isMainPage);
1250 } else {
1251 TriggerPageUpdate(page->GetPageId());
1252 }
1253 }
1254
AddPageLocked(const RefPtr<JsAcePage> & page)1255 void PluginFrontendDelegate::AddPageLocked(const RefPtr<JsAcePage>& page)
1256 {
1257 auto result = pageMap_.try_emplace(page->GetPageId(), page);
1258 if (!result.second) {
1259 LOGW("the page has already in the map");
1260 }
1261 }
1262
SetCurrentPage(int32_t pageId)1263 void PluginFrontendDelegate::SetCurrentPage(int32_t pageId)
1264 {
1265 auto page = GetPage(pageId);
1266 if (page != nullptr) {
1267 jsAccessibilityManager_->SetVersion(AccessibilityVersion::JS_DECLARATIVE_VERSION);
1268 jsAccessibilityManager_->SetRunningPage(page);
1269 taskExecutor_->PostTask([updatePage = updatePage_, page] { updatePage(page); },
1270 TaskExecutor::TaskType::JS, "ArkUIPluginSetCurrentPage");
1271 } else {
1272 LOGE("PluginFrontendDelegate SetCurrentPage page is null.");
1273 }
1274 }
1275
OnPushPageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1276 void PluginFrontendDelegate::OnPushPageSuccess(
1277 const RefPtr<JsAcePage>& page, const std::string& url)
1278 {
1279 std::lock_guard<std::mutex> lock(mutex_);
1280 AddPageLocked(page);
1281 pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url });
1282 if (Container::IsCurrentUseNewPipeline()) {
1283 FireDeclarativeOnUpdateWithValueParamsCallback(page->GetPluginComponentJsonData());
1284 } else {
1285 page->FireDeclarativeOnUpdateWithValueParamsCallback(page->GetPluginComponentJsonData());
1286 }
1287 if (pageRouteStack_.size() >= MAX_ROUTER_STACK) {
1288 isRouteStackFull_ = true;
1289 EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, page->GetUrl());
1290 }
1291 }
1292
OnPopToPageSuccess(const std::string & url)1293 void PluginFrontendDelegate::OnPopToPageSuccess(const std::string& url)
1294 {
1295 std::lock_guard<std::mutex> lock(mutex_);
1296 while (!pageRouteStack_.empty()) {
1297 if (pageRouteStack_.back().url == url) {
1298 break;
1299 }
1300 OnPageDestroy(pageRouteStack_.back().pageId);
1301 pageMap_.erase(pageRouteStack_.back().pageId);
1302 pageParamMap_.erase(pageRouteStack_.back().pageId);
1303 pageRouteStack_.pop_back();
1304 }
1305
1306 if (isRouteStackFull_) {
1307 isRouteStackFull_ = false;
1308 }
1309 }
1310
PopToPage(const std::string & url)1311 void PluginFrontendDelegate::PopToPage(const std::string& url)
1312 {
1313 taskExecutor_->PostTask(
1314 [weak = AceType::WeakClaim(this), url] {
1315 auto delegate = weak.Upgrade();
1316 CHECK_NULL_VOID(delegate);
1317 auto pageId = delegate->GetPageIdByUrl(url);
1318 if (pageId == INVALID_PAGE_ID) {
1319 return;
1320 }
1321 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1322 CHECK_NULL_VOID(pipelineContext);
1323 if (!pipelineContext->CanPopPage()) {
1324 delegate->ResetStagingPage();
1325 return;
1326 }
1327 delegate->OnPageHide();
1328 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1329 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1330 [weak, url, pageId](
1331 const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1332 auto delegate = weak.Upgrade();
1333 if (delegate) {
1334 delegate->PopToPageTransitionListener(event, url, pageId);
1335 }
1336 });
1337 pipelineContext->PopToPage(pageId);
1338 },
1339 TaskExecutor::TaskType::UI, "ArkUIPluginPopToPage");
1340 }
1341
PopToPageTransitionListener(const TransitionEvent & event,const std::string & url,int32_t pageId)1342 void PluginFrontendDelegate::PopToPageTransitionListener(
1343 const TransitionEvent& event, const std::string& url, int32_t pageId)
1344 {
1345 if (event == TransitionEvent::POP_END) {
1346 OnPopToPageSuccess(url);
1347 SetCurrentPage(pageId);
1348 OnPageShow();
1349 OnMediaQueryUpdate();
1350 }
1351 }
1352
OnPopPageSuccess()1353 int32_t PluginFrontendDelegate::OnPopPageSuccess()
1354 {
1355 std::lock_guard<std::mutex> lock(mutex_);
1356 pageMap_.erase(pageRouteStack_.back().pageId);
1357 pageParamMap_.erase(pageRouteStack_.back().pageId);
1358 pageRouteStack_.pop_back();
1359 if (isRouteStackFull_) {
1360 isRouteStackFull_ = false;
1361 }
1362 if (!pageRouteStack_.empty()) {
1363 return pageRouteStack_.back().pageId;
1364 }
1365 return INVALID_PAGE_ID;
1366 }
1367
PopPage()1368 void PluginFrontendDelegate::PopPage()
1369 {
1370 taskExecutor_->PostTask(
1371 [weak = AceType::WeakClaim(this)] {
1372 auto delegate = weak.Upgrade();
1373 CHECK_NULL_VOID(delegate);
1374 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1375 CHECK_NULL_VOID(pipelineContext);
1376 if (delegate->GetStackSize() == 1) {
1377 if (delegate->disallowPopLastPage_) {
1378 LOGW("Not allow back because this is the last page!");
1379 return;
1380 }
1381 delegate->OnPageHide();
1382 delegate->OnPageDestroy(delegate->GetRunningPageId());
1383 delegate->OnPopPageSuccess();
1384 pipelineContext->Finish();
1385 return;
1386 }
1387 if (!pipelineContext->CanPopPage()) {
1388 delegate->ResetStagingPage();
1389 return;
1390 }
1391 delegate->OnPageHide();
1392 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1393 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1394 [weak, destroyPageId = delegate->GetRunningPageId()](
1395 const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1396 auto delegate = weak.Upgrade();
1397 if (delegate) {
1398 delegate->PopPageTransitionListener(event, destroyPageId);
1399 }
1400 });
1401 pipelineContext->PopPage();
1402 },
1403 TaskExecutor::TaskType::UI, "ArkUIPluginPopPage");
1404 }
1405
PopPageTransitionListener(const TransitionEvent & event,int32_t destroyPageId)1406 void PluginFrontendDelegate::PopPageTransitionListener(
1407 const TransitionEvent& event, int32_t destroyPageId)
1408 {
1409 if (event == TransitionEvent::POP_END) {
1410 OnPageDestroy(destroyPageId);
1411 auto pageId = OnPopPageSuccess();
1412 SetCurrentPage(pageId);
1413 OnPageShow();
1414 OnMediaQueryUpdate();
1415 }
1416 }
1417
OnClearInvisiblePagesSuccess()1418 int32_t PluginFrontendDelegate::OnClearInvisiblePagesSuccess()
1419 {
1420 std::lock_guard<std::mutex> lock(mutex_);
1421 PageInfo pageInfo = std::move(pageRouteStack_.back());
1422 pageRouteStack_.pop_back();
1423 for (const auto& info : pageRouteStack_) {
1424 OnPageDestroy(info.pageId);
1425 pageMap_.erase(info.pageId);
1426 pageParamMap_.erase(info.pageId);
1427 }
1428 pageRouteStack_.clear();
1429 int32_t resPageId = pageInfo.pageId;
1430 pageRouteStack_.emplace_back(std::move(pageInfo));
1431 if (isRouteStackFull_) {
1432 isRouteStackFull_ = false;
1433 }
1434 return resPageId;
1435 }
1436
ClearInvisiblePages()1437 void PluginFrontendDelegate::ClearInvisiblePages()
1438 {
1439 taskExecutor_->PostTask(
1440 [weak = AceType::WeakClaim(this)] {
1441 auto delegate = weak.Upgrade();
1442 CHECK_NULL_VOID(delegate);
1443 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1444 CHECK_NULL_VOID(pipelineContext);
1445 if (pipelineContext->ClearInvisiblePages()) {
1446 auto pageId = delegate->OnClearInvisiblePagesSuccess();
1447 delegate->SetCurrentPage(pageId);
1448 }
1449 },
1450 TaskExecutor::TaskType::UI, "ArkUIPluginClearInvisiblePages");
1451 }
1452
OnReplacePageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1453 void PluginFrontendDelegate::OnReplacePageSuccess(
1454 const RefPtr<JsAcePage>& page, const std::string& url)
1455 {
1456 CHECK_NULL_VOID(page);
1457 std::lock_guard<std::mutex> lock(mutex_);
1458 AddPageLocked(page);
1459 if (!pageRouteStack_.empty()) {
1460 pageMap_.erase(pageRouteStack_.back().pageId);
1461 pageParamMap_.erase(pageRouteStack_.back().pageId);
1462 pageRouteStack_.pop_back();
1463 }
1464 pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url});
1465 }
1466
ReplacePage(const RefPtr<JsAcePage> & page,const std::string & url)1467 void PluginFrontendDelegate::ReplacePage(
1468 const RefPtr<JsAcePage>& page, const std::string& url)
1469 {
1470 // Pop all JS command and execute them in UI thread.
1471 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1472 page->PopAllCommands(*jsCommands);
1473
1474 auto pipelineContext = pipelineContextHolder_.Get();
1475 page->SetPipelineContext(pipelineContext);
1476 taskExecutor_->PostTask(
1477 [weak = AceType::WeakClaim(this), page, url, jsCommands] {
1478 auto delegate = weak.Upgrade();
1479 CHECK_NULL_VOID(delegate);
1480 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1481 CHECK_NULL_VOID(pipelineContext);
1482 // Flush all JS commands.
1483 for (const auto& command : *jsCommands) {
1484 command->Execute(page);
1485 }
1486 // Just clear all dirty nodes.
1487 page->ClearAllDirtyNodes();
1488 page->GetDomDocument()->HandleComponentPostBinding();
1489 if (pipelineContext->GetAccessibilityManager()) {
1490 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1491 }
1492 if (pipelineContext->CanReplacePage()) {
1493 delegate->OnPageHide();
1494 delegate->OnPageDestroy(delegate->GetRunningPageId());
1495 delegate->OnPrePageChange(page);
1496 pipelineContext->ReplacePage(page->BuildPage(url), page->GetStageElement());
1497 delegate->OnReplacePageSuccess(page, url);
1498 delegate->SetCurrentPage(page->GetPageId());
1499 delegate->OnMediaQueryUpdate();
1500 } else {
1501 // This page has been loaded but become useless now, the corresponding js instance
1502 // must be destroyed to avoid memory leak.
1503 delegate->OnPageDestroy(page->GetPageId());
1504 delegate->ResetStagingPage();
1505 }
1506 delegate->isStagingPageExist_ = false;
1507 },
1508 TaskExecutor::TaskType::UI, "ArkUIPluginReplacePage");
1509 }
1510
LoadReplacePage(int32_t pageId,const PageTarget & target,const std::string & params)1511 void PluginFrontendDelegate::LoadReplacePage(int32_t pageId, const PageTarget& target, const std::string& params)
1512 {
1513 {
1514 std::lock_guard<std::mutex> lock(mutex_);
1515 pageId_ = pageId;
1516 pageParamMap_[pageId] = params;
1517 }
1518 auto url = target.url;
1519 if (pageId == INVALID_PAGE_ID) {
1520 LOGE("PluginFrontendDelegate, invalid page id");
1521 EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1522 return;
1523 }
1524 if (isStagingPageExist_) {
1525 LOGE("PluginFrontendDelegate, replace page failed, waiting for current page loading finish.");
1526 EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1527 return;
1528 }
1529 isStagingPageExist_ = true;
1530 auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1531 auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1532 page->SetPageParams(params);
1533 taskExecutor_->PostTask(
1534 [page, url, weak = AceType::WeakClaim(this)] {
1535 auto delegate = weak.Upgrade();
1536 if (delegate) {
1537 delegate->loadJs_(url, page, false);
1538 delegate->ReplacePage(page, url);
1539 }
1540 },
1541 TaskExecutor::TaskType::JS, "ArkUIPluginLoadReplacePage");
1542 }
1543
SetColorMode(ColorMode colorMode)1544 void PluginFrontendDelegate::SetColorMode(ColorMode colorMode)
1545 {
1546 OnMediaQueryUpdate();
1547 }
1548
RebuildAllPages()1549 void PluginFrontendDelegate::RebuildAllPages()
1550 {
1551 std::unordered_map<int32_t, RefPtr<JsAcePage>> pages;
1552 {
1553 std::lock_guard<std::mutex> lock(mutex_);
1554 pages.insert(pageMap_.begin(), pageMap_.end());
1555 }
1556 for (const auto& [pageId, page] : pages) {
1557 page->FireDeclarativeOnPageRefreshCallback();
1558 TriggerPageUpdate(page->GetPageId(), true);
1559 }
1560 }
1561
OnPageShow()1562 void PluginFrontendDelegate::OnPageShow()
1563 {
1564 auto pageId = GetRunningPageId();
1565 auto page = GetPage(pageId);
1566 if (page) {
1567 page->FireDeclarativeOnPageAppearCallback();
1568 }
1569 FireAsyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
1570 }
1571
OnPageHide()1572 void PluginFrontendDelegate::OnPageHide()
1573 {
1574 auto pageId = GetRunningPageId();
1575 auto page = GetPage(pageId);
1576 if (page) {
1577 page->FireDeclarativeOnPageDisAppearCallback();
1578 }
1579 FireAsyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
1580 }
1581
OnPageDestroy(int32_t pageId)1582 void PluginFrontendDelegate::OnPageDestroy(int32_t pageId)
1583 {
1584 taskExecutor_->PostTask(
1585 [weak = AceType::WeakClaim(this), pageId] {
1586 auto delegate = weak.Upgrade();
1587 if (delegate) {
1588 delegate->destroyPage_(pageId);
1589 delegate->RecyclePageId(pageId);
1590 }
1591 },
1592 TaskExecutor::TaskType::JS, "ArkUIPluginPageDestroy");
1593 }
1594
GetRunningPageId() const1595 int32_t PluginFrontendDelegate::GetRunningPageId() const
1596 {
1597 std::lock_guard<std::mutex> lock(mutex_);
1598 if (pageRouteStack_.empty()) {
1599 return INVALID_PAGE_ID;
1600 }
1601 return pageRouteStack_.back().pageId;
1602 }
1603
GetRunningPageUrl() const1604 std::string PluginFrontendDelegate::GetRunningPageUrl() const
1605 {
1606 std::lock_guard<std::mutex> lock(mutex_);
1607 if (pageRouteStack_.empty()) {
1608 return std::string();
1609 }
1610 const auto& pageUrl = pageRouteStack_.back().url;
1611 auto pos = pageUrl.rfind(".js");
1612 if (pos == pageUrl.length() - JS_HEADER_OFFSET) {
1613 return pageUrl.substr(0, pos);
1614 }
1615 return pageUrl;
1616 }
1617
GetPageIdByUrl(const std::string & url)1618 int32_t PluginFrontendDelegate::GetPageIdByUrl(const std::string& url)
1619 {
1620 std::lock_guard<std::mutex> lock(mutex_);
1621 auto pageIter = std::find_if(std::rbegin(pageRouteStack_), std::rend(pageRouteStack_),
1622 [&url](const PageInfo& pageRoute) { return url == pageRoute.url; });
1623 if (pageIter != std::rend(pageRouteStack_)) {
1624 LOGW("GetPageIdByUrl pageId=%{private}d url=%{private}s", pageIter->pageId, url.c_str());
1625 return pageIter->pageId;
1626 }
1627 return INVALID_PAGE_ID;
1628 }
1629
GetPage(int32_t pageId) const1630 RefPtr<JsAcePage> PluginFrontendDelegate::GetPage(int32_t pageId) const
1631 {
1632 std::lock_guard<std::mutex> lock(mutex_);
1633 auto itPage = pageMap_.find(pageId);
1634 if (itPage == pageMap_.end()) {
1635 LOGE("the page is not in the map");
1636 return nullptr;
1637 }
1638 return itPage->second;
1639 }
1640
RegisterFont(const std::string & familyName,const std::string & familySrc,const std::string & bundleName,const std::string & moduleName)1641 void PluginFrontendDelegate::RegisterFont(const std::string& familyName, const std::string& familySrc,
1642 const std::string& bundleName, const std::string& moduleName)
1643 {
1644 pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc, bundleName, moduleName);
1645 }
1646
GetSystemFontList(std::vector<std::string> & fontList)1647 void PluginFrontendDelegate::GetSystemFontList(std::vector<std::string>& fontList)
1648 {
1649 pipelineContextHolder_.Get()->GetSystemFontList(fontList);
1650 }
1651
GetSystemFont(const std::string & fontName,FontInfo & fontInfo)1652 bool PluginFrontendDelegate::GetSystemFont(const std::string& fontName, FontInfo& fontInfo)
1653 {
1654 return pipelineContextHolder_.Get()->GetSystemFont(fontName, fontInfo);
1655 }
1656
HandleImage(const std::string & src,std::function<void (bool,int32_t,int32_t)> && callback)1657 void PluginFrontendDelegate::HandleImage(
1658 const std::string& src, std::function<void(bool, int32_t, int32_t)>&& callback)
1659 {
1660 if (src.empty() || !callback) {
1661 return;
1662 }
1663 auto loadCallback = [jsCallback = std::move(callback), taskExecutor = taskExecutor_](
1664 bool success, int32_t width, int32_t height) {
1665 taskExecutor->PostTask(
1666 [callback = std::move(jsCallback), success, width, height] { callback(success, width, height); },
1667 TaskExecutor::TaskType::JS, "ArkUIPluginHandleImage");
1668 };
1669 pipelineContextHolder_.Get()->TryLoadImageInfo(src, std::move(loadCallback));
1670 }
1671
PushJsCallbackToRenderNode(NodeId id,double ratio,std::function<void (bool,double)> && callback)1672 void PluginFrontendDelegate::PushJsCallbackToRenderNode(NodeId id, double ratio,
1673 std::function<void(bool, double)>&& callback)
1674 {
1675 LOGW("Not implement in declarative frontend.");
1676 }
1677
RequestAnimationFrame(const std::string & callbackId)1678 void PluginFrontendDelegate::RequestAnimationFrame(const std::string& callbackId)
1679 {
1680 CancelableCallback<void()> cancelableTask;
1681 cancelableTask.Reset([callbackId, call = requestAnimationCallback_, weak = AceType::WeakClaim(this)] {
1682 auto delegate = weak.Upgrade();
1683 if (delegate && call) {
1684 call(callbackId, delegate->GetSystemRealTime());
1685 }
1686 });
1687 animationFrameTaskMap_.try_emplace(callbackId, cancelableTask);
1688 animationFrameTaskIds_.emplace(callbackId);
1689 }
1690
GetSystemRealTime()1691 uint64_t PluginFrontendDelegate::GetSystemRealTime()
1692 {
1693 struct timespec ts;
1694 clock_gettime(CLOCK_REALTIME, &ts);
1695 return ts.tv_sec * TO_MILLI + ts.tv_nsec / NANO_TO_MILLI;
1696 }
1697
CancelAnimationFrame(const std::string & callbackId)1698 void PluginFrontendDelegate::CancelAnimationFrame(const std::string& callbackId)
1699 {
1700 auto animationTaskIter = animationFrameTaskMap_.find(callbackId);
1701 if (animationTaskIter != animationFrameTaskMap_.end()) {
1702 animationTaskIter->second.Cancel();
1703 animationFrameTaskMap_.erase(animationTaskIter);
1704 } else {
1705 LOGW("cancelAnimationFrame callbackId not found");
1706 }
1707 }
1708
FlushAnimationTasks()1709 void PluginFrontendDelegate::FlushAnimationTasks()
1710 {
1711 while (!animationFrameTaskIds_.empty()) {
1712 const auto& callbackId = animationFrameTaskIds_.front();
1713 if (!callbackId.empty()) {
1714 auto taskIter = animationFrameTaskMap_.find(callbackId);
1715 if (taskIter != animationFrameTaskMap_.end()) {
1716 taskExecutor_->PostTask(taskIter->second, TaskExecutor::TaskType::JS, "ArkUIPluginFlushAnimationTask");
1717 }
1718 }
1719 animationFrameTaskIds_.pop();
1720 }
1721 }
1722
GetAnimationJsTask()1723 SingleTaskExecutor PluginFrontendDelegate::GetAnimationJsTask()
1724 {
1725 return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::JS);
1726 }
1727
GetUiTask()1728 SingleTaskExecutor PluginFrontendDelegate::GetUiTask()
1729 {
1730 return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::UI);
1731 }
1732
AttachPipelineContext(const RefPtr<PipelineBase> & context)1733 void PluginFrontendDelegate::AttachPipelineContext(const RefPtr<PipelineBase>& context)
1734 {
1735 CHECK_NULL_VOID(context);
1736 context->SetOnPageShow([weak = AceType::WeakClaim(this)] {
1737 auto delegate = weak.Upgrade();
1738 if (delegate) {
1739 delegate->OnPageShow();
1740 }
1741 });
1742 context->SetAnimationCallback([weak = AceType::WeakClaim(this)] {
1743 auto delegate = weak.Upgrade();
1744 if (delegate) {
1745 delegate->FlushAnimationTasks();
1746 }
1747 });
1748 pipelineContextHolder_.Attach(context);
1749 jsAccessibilityManager_->SetPipelineContext(context);
1750 jsAccessibilityManager_->InitializeCallback();
1751 }
1752
GetPipelineContext()1753 RefPtr<PipelineBase> PluginFrontendDelegate::GetPipelineContext()
1754 {
1755 return pipelineContextHolder_.Get();
1756 }
1757
UpdatePlugin(const std::string & content)1758 void PluginFrontendDelegate::UpdatePlugin(const std::string& content)
1759 {
1760 auto pageId = GetRunningPageId();
1761 auto page = GetPage(pageId);
1762 if (Container::IsCurrentUseNewPipeline()) {
1763 FireDeclarativeOnUpdateWithValueParamsCallback(content);
1764 return;
1765 }
1766 if (page) {
1767 page->FireDeclarativeOnUpdateWithValueParamsCallback(content);
1768 }
1769 }
1770 } // namespace OHOS::Ace::Framework
1771