1 /*
2 * Copyright (c) 2021-2023 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/js_frontend/frontend_delegate_impl.h"
17
18 #include "base/i18n/localization.h"
19 #include "base/log/event_report.h"
20 #include "base/resource/ace_res_config.h"
21 #include "core/components/toast/toast_component.h"
22
23 namespace OHOS::Ace::Framework {
24 namespace {
25
26 constexpr int32_t INVALID_PAGE_ID = -1;
27 constexpr int32_t MAX_ROUTER_STACK = 32;
28 constexpr int32_t TOAST_TIME_MAX = 10000; // ms
29 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
30 constexpr int32_t MAX_PAGE_ID_SIZE = sizeof(uint64_t) * 8;
31 constexpr int32_t NANO_TO_MILLI = 1000000; // nanosecond to millisecond
32 constexpr int32_t TO_MILLI = 1000; // second to millisecond
33 constexpr int32_t COMPATIBLE_VERSION = 7;
34 constexpr int32_t WEB_FEATURE_VERSION = 6;
35 constexpr int32_t CALLBACK_ERRORCODE_COMPLETE = 2;
36
37 const char MANIFEST_JSON[] = "manifest.json";
38 const char FILE_TYPE_JSON[] = ".json";
39 const char I18N_FOLDER[] = "i18n/";
40 const char RESOURCES_FOLDER[] = "resources/";
41 const char STYLES_FOLDER[] = "styles/";
42 const char I18N_FILE_SUFFIX[] = "/properties/i18n.json";
43
44 } // namespace
45
GenerateNextPageId()46 int32_t FrontendDelegateImpl::GenerateNextPageId()
47 {
48 for (int32_t idx = 0; idx < MAX_PAGE_ID_SIZE; ++idx) {
49 uint64_t bitMask = (1ULL << idx);
50 if ((bitMask & pageIdPool_.fetch_or(bitMask, std::memory_order_relaxed)) == 0) {
51 return idx;
52 }
53 }
54 return INVALID_PAGE_ID;
55 }
56
RecyclePageId(int32_t pageId)57 void FrontendDelegateImpl::RecyclePageId(int32_t pageId)
58 {
59 if (pageId < 0 && pageId >= MAX_PAGE_ID_SIZE) {
60 return;
61 }
62 uint64_t bitMask = (1ULL << pageId);
63 pageIdPool_.fetch_and(~bitMask, std::memory_order_relaxed);
64 }
65
FrontendDelegateImpl(const FrontendDelegateImplBuilder & builder)66 FrontendDelegateImpl::FrontendDelegateImpl(const FrontendDelegateImplBuilder& builder)
67 : loadJs_(builder.loadCallback), dispatcherCallback_(builder.transferCallback),
68 asyncEvent_(builder.asyncEventCallback), syncEvent_(builder.syncEventCallback),
69 externalEvent_(builder.externalEventCallback),
70 updatePage_(builder.updatePageCallback), resetStagingPage_(builder.resetStagingPageCallback),
71 destroyPage_(builder.destroyPageCallback), destroyApplication_(builder.destroyApplicationCallback),
72 updateApplicationState_(builder.updateApplicationStateCallback),
73 onStartContinuationCallBack_(builder.onStartContinuationCallBack),
74 onCompleteContinuationCallBack_(builder.onCompleteContinuationCallBack),
75 onRemoteTerminatedCallBack_(builder.onRemoteTerminatedCallBack),
76 onSaveDataCallBack_(builder.onSaveDataCallBack),
77 onRestoreDataCallBack_(builder.onRestoreDataCallBack),
78 timer_(builder.timerCallback), mediaQueryCallback_(builder.mediaQueryCallback),
79 requestAnimationCallback_(builder.requestAnimationCallback), jsCallback_(builder.jsCallback),
80 manifestParser_(AceType::MakeRefPtr<ManifestParser>()),
81 jsAccessibilityManager_(AccessibilityNodeManager::Create()),
82 mediaQueryInfo_(AceType::MakeRefPtr<MediaQueryInfo>()), taskExecutor_(builder.taskExecutor),
83 callNativeHandler_(builder.callNativeHandler)
84 {}
85
~FrontendDelegateImpl()86 FrontendDelegateImpl::~FrontendDelegateImpl()
87 {
88 CHECK_RUN_ON(JS);
89 LOGI("DelegateImpl destroyed");
90 }
91
ParseManifest()92 void FrontendDelegateImpl::ParseManifest()
93 {
94 std::call_once(onceFlag_, [weak = AceType::WeakClaim(this)]() {
95 std::string jsonContent;
96 auto delegate = weak.Upgrade();
97 if (delegate) {
98 if (!delegate->GetAssetContent(MANIFEST_JSON, jsonContent)) {
99 LOGE("RunPage parse manifest.json failed");
100 EventReport::SendFormException(FormExcepType::RUN_PAGE_ERR);
101 return;
102 }
103 delegate->manifestParser_->Parse(jsonContent);
104 auto task = [delegate]() {
105 delegate->pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
106 delegate->manifestParser_->GetAppInfo()->ParseI18nJsonInfo();
107 };
108 delegate->taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS, "ArkUIParseI18nJsonInfo");
109 }
110 });
111 }
112
RunPage(const std::string & url,const std::string & params)113 UIContentErrorCode FrontendDelegateImpl::RunPage(const std::string& url, const std::string& params)
114 {
115 ACE_SCOPED_TRACE("FrontendDelegateImpl::RunPage");
116
117 auto routerBackCallback = [weak = WeakClaim(this)](const std::string& urlPath) {
118 auto delegate = weak.Upgrade();
119 if (!delegate) {
120 return false;
121 }
122 delegate->Push(urlPath, "");
123 return true;
124 };
125 DelegateClient::GetInstance().RegisterRouterPushCallback(routerBackCallback);
126
127 auto getWebPageUrlCallback = [weak = WeakClaim(this)](std::string& pageUrl, int32_t& pageId) {
128 auto delegate = weak.Upgrade();
129 if (!delegate) {
130 return false;
131 }
132 pageUrl = delegate->GetRunningPageUrl();
133 pageId = delegate->GetRunningPageId();
134 return true;
135 };
136 DelegateClient::GetInstance().RegisterGetWebPageUrlCallback(getWebPageUrlCallback);
137
138 auto isPagePathInvalidCallback = [weak = WeakClaim(this)](bool& isPageEmpty) {
139 auto delegate = weak.Upgrade();
140 if (!delegate) {
141 return false;
142 }
143 isPageEmpty = delegate->GetPagePathInvalidFlag();
144 return true;
145 };
146 DelegateClient::GetInstance().RegisterIsPagePathInvalidCallback(isPagePathInvalidCallback);
147
148 ParseManifest();
149 if (!url.empty()) {
150 mainPagePath_ = manifestParser_->GetRouter()->GetPagePath(url);
151 if (mainPagePath_.empty()) {
152 mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
153 }
154 } else {
155 mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
156 }
157 return LoadPage(GenerateNextPageId(), mainPagePath_, true, params);
158 }
159
ChangeLocale(const std::string & language,const std::string & countryOrRegion)160 void FrontendDelegateImpl::ChangeLocale(const std::string& language, const std::string& countryOrRegion)
161 {
162 taskExecutor_->PostTask(
163 [language, countryOrRegion]() { AceApplicationInfo::GetInstance().ChangeLocale(language, countryOrRegion); },
164 TaskExecutor::TaskType::PLATFORM, "ArkUIChangeLocale");
165 }
166
GetI18nData(std::unique_ptr<JsonValue> & json)167 void FrontendDelegateImpl::GetI18nData(std::unique_ptr<JsonValue>& json)
168 {
169 auto data = JsonUtil::CreateArray(true);
170 GetConfigurationCommon(I18N_FOLDER, data);
171 auto i18nData = JsonUtil::Create(true);
172 i18nData->Put("resources", data);
173 json->Put("i18n", i18nData);
174 }
175
GetResourceConfiguration(std::unique_ptr<JsonValue> & json)176 void FrontendDelegateImpl::GetResourceConfiguration(std::unique_ptr<JsonValue>& json)
177 {
178 auto data = JsonUtil::CreateArray(true);
179 GetConfigurationCommon(RESOURCES_FOLDER, data);
180 json->Put("resourcesConfiguration", data);
181 }
182
GetConfigurationCommon(const std::string & filePath,std::unique_ptr<JsonValue> & data)183 void FrontendDelegateImpl::GetConfigurationCommon(const std::string& filePath, std::unique_ptr<JsonValue>& data)
184 {
185 std::vector<std::string> files;
186 if (assetManager_) {
187 assetManager_->GetAssetList(filePath, files);
188 }
189
190 std::vector<std::string> fileNameList;
191 for (const auto& file : files) {
192 if (EndWith(file, FILE_TYPE_JSON) && !StartWith(file, STYLES_FOLDER)) {
193 std::string tmp = file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1));
194 size_t pos = tmp.find_last_of("/");
195 pos = (pos == std::string::npos) ? 0 : (pos + 1);
196 fileNameList.emplace_back(tmp.substr(pos, tmp.size() - pos));
197 }
198 }
199
200 std::vector<std::string> priorityFileName;
201 if (filePath.compare(I18N_FOLDER) == 0) {
202 auto localeTag = AceApplicationInfo::GetInstance().GetLocaleTag();
203 priorityFileName = AceResConfig::GetLocaleFallback(localeTag, fileNameList);
204 } else {
205 priorityFileName = AceResConfig::GetResourceFallback(fileNameList);
206 }
207
208 for (const auto& fileName : priorityFileName) {
209 auto fileFullPath = filePath + fileName + std::string(FILE_TYPE_JSON);
210 #if !defined(PREVIEW)
211 if (filePath.compare(I18N_FOLDER) == 0) {
212 GetAssetFromI18n(fileFullPath, data);
213 continue;
214 }
215 #endif
216 std::string content;
217 if (GetAssetContent(fileFullPath, content)) {
218 auto fileData = ParseFileData(content);
219 if (fileData == nullptr) {
220 LOGW("parse %{private}s.json i18n content failed", filePath.c_str());
221 } else {
222 data->Put(fileData);
223 }
224 }
225 }
226 }
227
GetAssetFromI18n(const std::string & fileFullPath,std::unique_ptr<JsonValue> & data)228 void FrontendDelegateImpl::GetAssetFromI18n(const std::string& fileFullPath, std::unique_ptr<JsonValue>& data)
229 {
230 if (!assetManager_) {
231 return;
232 }
233 auto jsAssetVector = assetManager_->GetAssetFromI18n(fileFullPath);
234 for (auto& jsAsset : jsAssetVector) {
235 auto bufLen = jsAsset->GetSize();
236 auto buffer = jsAsset->GetData();
237 if ((buffer == nullptr) || (bufLen <= 0)) {
238 continue;
239 }
240 std::string content;
241 content.assign(buffer, buffer + bufLen);
242 auto fileData = ParseFileData(content);
243 if (fileData) {
244 data->Put(fileData);
245 }
246 }
247 }
248
OnJsCallback(const std::string & callbackId,const std::string & data)249 void FrontendDelegateImpl::OnJsCallback(const std::string& callbackId, const std::string& data)
250 {
251 taskExecutor_->PostTask(
252 [weak = AceType::WeakClaim(this), callbackId, args = std::move(data)] {
253 auto delegate = weak.Upgrade();
254 if (delegate) {
255 delegate->jsCallback_(callbackId, args);
256 }
257 },
258 TaskExecutor::TaskType::JS, "ArkUIHandleJsCallback");
259 }
260
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher) const261 void FrontendDelegateImpl::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) const
262 {
263 taskExecutor_->PostTask([dispatcherCallback = dispatcherCallback_, dispatcher] { dispatcherCallback(dispatcher); },
264 TaskExecutor::TaskType::JS, "ArkUISetJsMessageDispatcher");
265 }
266
TransferComponentResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data)267 void FrontendDelegateImpl::TransferComponentResponseData(int32_t callbackId, int32_t code, std::vector<uint8_t>&& data)
268 {
269 WeakPtr<PipelineBase> contextWeak(pipelineContextHolder_.Get());
270 taskExecutor_->PostTask(
271 [callbackId, data = std::move(data), contextWeak]() mutable {
272 auto context = contextWeak.Upgrade();
273 if (!context) {
274 LOGE("context is null");
275 } else if (!context->GetMessageBridge()) {
276 LOGE("messageBridge is null");
277 } else {
278 context->GetMessageBridge()->HandleCallback(callbackId, std::move(data));
279 }
280 },
281 TaskExecutor::TaskType::UI, "ArkUITransferComponentResponseData");
282 }
283
TransferJsResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const284 void FrontendDelegateImpl::TransferJsResponseData(int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
285 {
286 auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
287 taskExecutor_->PostTask(
288 [callbackId, code, data = std::move(data), weak]() mutable {
289 auto groupJsBridge = weak.Upgrade();
290 if (groupJsBridge) {
291 groupJsBridge->TriggerModuleJsCallback(callbackId, code, std::move(data));
292 }
293 },
294 TaskExecutor::TaskType::JS, "ArkUITransferJsResponseData");
295 }
296
297 #if defined(PREVIEW)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const298 void FrontendDelegateImpl::TransferJsResponseDataPreview(
299 int32_t callbackId, int32_t code, ResponseData responseData) const
300 {
301 LOGI("JsFrontend TransferJsResponseDataPreview");
302 auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
303 taskExecutor_->PostTask(
304 [callbackId, code, responseData, weak]() mutable {
305 auto groupJsBridge = weak.Upgrade();
306 if (groupJsBridge) {
307 groupJsBridge->TriggerModuleJsCallbackPreview(callbackId, code, responseData);
308 }
309 },
310 TaskExecutor::TaskType::JS, "ArkUITransferJsResponseData");
311 }
312 #endif
313
TransferJsPluginGetError(int32_t callbackId,int32_t errorCode,std::string && errorMessage) const314 void FrontendDelegateImpl::TransferJsPluginGetError(
315 int32_t callbackId, int32_t errorCode, std::string&& errorMessage) const
316 {
317 auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
318 taskExecutor_->PostTask(
319 [callbackId, errorCode, errorMessage = std::move(errorMessage), weak]() mutable {
320 auto groupJsBridge = weak.Upgrade();
321 if (groupJsBridge) {
322 groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, errorCode, std::move(errorMessage));
323 }
324 },
325 TaskExecutor::TaskType::JS, "ArkUITransferJsPluginGetError");
326 }
327
TransferJsEventData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const328 void FrontendDelegateImpl::TransferJsEventData(int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
329 {
330 auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
331 taskExecutor_->PostTask(
332 [callbackId, code, data = std::move(data), weak]() mutable {
333 auto groupJsBridge = weak.Upgrade();
334 if (groupJsBridge) {
335 groupJsBridge->TriggerEventJsCallback(callbackId, code, std::move(data));
336 }
337 },
338 TaskExecutor::TaskType::JS, "ArkUITransferJsEventData");
339 }
340
LoadPluginJsCode(std::string && jsCode) const341 void FrontendDelegateImpl::LoadPluginJsCode(std::string&& jsCode) const
342 {
343 auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
344 taskExecutor_->PostTask(
345 [jsCode = std::move(jsCode), weak]() mutable {
346 auto groupJsBridge = weak.Upgrade();
347 if (groupJsBridge) {
348 groupJsBridge->LoadPluginJsCode(std::move(jsCode));
349 }
350 },
351 TaskExecutor::TaskType::JS, "ArkUILoadPluginJsCode");
352 }
353
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen) const354 void FrontendDelegateImpl::LoadPluginJsByteCode(std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen) const
355 {
356 auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
357 taskExecutor_->PostTask(
358 [jsCode = std::move(jsCode), jsCodeLen = std::move(jsCodeLen), weak]() mutable {
359 auto groupJsBridge = weak.Upgrade();
360 if (groupJsBridge) {
361 groupJsBridge->LoadPluginJsByteCode(std::move(jsCode), std::move(jsCodeLen));
362 }
363 },
364 TaskExecutor::TaskType::JS, "ArkUILoadPluginJsByteCode");
365 }
366
OnPageBackPress()367 bool FrontendDelegateImpl::OnPageBackPress()
368 {
369 bool result = FireSyncEvent("_root", std::string("\"clickbackitem\","), std::string(""));
370 return result;
371 }
372
OnActive()373 void FrontendDelegateImpl::OnActive()
374 {
375 FireAsyncEvent("_root", std::string("\"viewactive\",null,null"), std::string(""));
376 }
377
OnInactive()378 void FrontendDelegateImpl::OnInactive()
379 {
380 FireAsyncEvent("_root", std::string("\"viewinactive\",null,null"), std::string(""));
381 FireAsyncEvent("_root", std::string("\"viewsuspended\",null,null"), std::string(""));
382 }
383
OnBackGround()384 void FrontendDelegateImpl::OnBackGround()
385 {
386 OnPageHide();
387 }
388
OnForeground()389 void FrontendDelegateImpl::OnForeground()
390 {
391 // first page show will be called by push page successfully
392 if (!isFirstNotifyShow_) {
393 OnPageShow();
394 }
395 isFirstNotifyShow_ = false;
396 }
397
OnStartContinuation()398 bool FrontendDelegateImpl::OnStartContinuation()
399 {
400 bool ret = false;
401 taskExecutor_->PostSyncTask(
402 [weak = AceType::WeakClaim(this), &ret] {
403 auto delegate = weak.Upgrade();
404 if (delegate && delegate->onStartContinuationCallBack_) {
405 ret = delegate->onStartContinuationCallBack_();
406 }
407 },
408 TaskExecutor::TaskType::JS, "ArkUIStartContinuationCallback");
409 if (!ret) {
410 ret = FireSyncEvent("_root", std::string("\"onStartContinuation\","), std::string(""));
411 }
412 return ret;
413 }
414
OnCompleteContinuation(int32_t code)415 void FrontendDelegateImpl::OnCompleteContinuation(int32_t code)
416 {
417 taskExecutor_->PostSyncTask(
418 [weak = AceType::WeakClaim(this), code] {
419 auto delegate = weak.Upgrade();
420 if (delegate && delegate->onCompleteContinuationCallBack_) {
421 delegate->onCompleteContinuationCallBack_(code);
422 }
423 },
424 TaskExecutor::TaskType::JS, "ArkUICompleteContinuationCallback");
425 FireSyncEvent("_root", std::string("\"onCompleteContinuation\","), std::to_string(code));
426 }
427
OnRemoteTerminated()428 void FrontendDelegateImpl::OnRemoteTerminated()
429 {
430 taskExecutor_->PostSyncTask(
431 [weak = AceType::WeakClaim(this)] {
432 auto delegate = weak.Upgrade();
433 if (delegate && delegate->onRemoteTerminatedCallBack_) {
434 delegate->onRemoteTerminatedCallBack_();
435 }
436 },
437 TaskExecutor::TaskType::JS, "ArkUIRemoteTerminatedCallback");
438 }
439
OnSaveData(std::string & data)440 void FrontendDelegateImpl::OnSaveData(std::string& data)
441 {
442 std::string savedData;
443 taskExecutor_->PostSyncTask(
444 [weak = AceType::WeakClaim(this), &savedData] {
445 auto delegate = weak.Upgrade();
446 if (delegate && delegate->onSaveDataCallBack_) {
447 delegate->onSaveDataCallBack_(savedData);
448 }
449 },
450 TaskExecutor::TaskType::JS, "ArkUISaveDataCallback");
451 if (savedData.empty()) {
452 FireSyncEvent("_root", std::string("\"onSaveData\","), std::string(""), savedData);
453 }
454 std::string pageUri = GetRunningPageUrl();
455 data = std::string("{\"url\":\"").append(pageUri).append("\",\"__remoteData\":").append(savedData).append("}");
456 }
457
OnRestoreData(const std::string & data)458 bool FrontendDelegateImpl::OnRestoreData(const std::string& data)
459 {
460 bool ret = false;
461 taskExecutor_->PostSyncTask(
462 [weak = AceType::WeakClaim(this), &data, &ret] {
463 auto delegate = weak.Upgrade();
464 if (delegate && delegate->onRestoreDataCallBack_) {
465 ret = delegate->onRestoreDataCallBack_(data);
466 }
467 },
468 TaskExecutor::TaskType::JS, "ArkUIRestoreDataCallback");
469 FireSyncEvent("_root", std::string("\"onSaveData\","), data);
470 return ret;
471 }
472
OnNewRequest(const std::string & data)473 void FrontendDelegateImpl::OnNewRequest(const std::string& data)
474 {
475 FireSyncEvent("_root", std::string("\"onNewRequest\","), data);
476 }
477
CallPopPage()478 void FrontendDelegateImpl::CallPopPage()
479 {
480 std::lock_guard<std::mutex> lock(mutex_);
481 auto& currentPage = pageRouteStack_.back();
482 if (!pageRouteStack_.empty() && currentPage.alertCallback) {
483 backUri_ = "";
484 taskExecutor_->PostTask(
485 [context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get()),
486 dialogProperties = pageRouteStack_.back().dialogProperties,
487 isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
488 if (context) {
489 context->ShowDialog(dialogProperties, isRightToLeft);
490 }
491 },
492 TaskExecutor::TaskType::UI, "ArkUIShowDialogBeforePopPage");
493 } else {
494 PopPage();
495 }
496 }
497
ResetStagingPage()498 void FrontendDelegateImpl::ResetStagingPage()
499 {
500 taskExecutor_->PostTask([resetStagingPage = resetStagingPage_] { resetStagingPage(); },
501 TaskExecutor::TaskType::JS, "ArkUIResetStagingPage");
502 }
503
OnApplicationDestroy(const std::string & packageName)504 void FrontendDelegateImpl::OnApplicationDestroy(const std::string& packageName)
505 {
506 taskExecutor_->PostSyncTask(
507 [destroyApplication = destroyApplication_, packageName] { destroyApplication(packageName); },
508 TaskExecutor::TaskType::JS, "ArkUIApplicationDestroyCallback");
509 }
510
OnApplicationUpdateState(const std::string & packageName,Frontend::State state)511 void FrontendDelegateImpl::OnApplicationUpdateState(const std::string& packageName, Frontend::State state)
512 {
513 taskExecutor_->PostSyncTask(
514 [updateApplication = updateApplicationState_, packageName, state] { updateApplication(packageName, state); },
515 TaskExecutor::TaskType::JS, "ArkUIApplicationUpdateStateCallback");
516 }
517
FireAsyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)518 void FrontendDelegateImpl::FireAsyncEvent(
519 const std::string& eventId, const std::string& param, const std::string& jsonArgs)
520 {
521 std::string args = param;
522 args.append(",null").append(",null"); // callback and dom changes
523 if (!jsonArgs.empty()) {
524 args.append(",").append(jsonArgs); // method args
525 }
526 taskExecutor_->PostTask(
527 [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
528 auto delegate = weak.Upgrade();
529 if (delegate) {
530 delegate->asyncEvent_(eventId, args);
531 }
532 },
533 TaskExecutor::TaskType::JS, "ArkUIFireAsyncEvent");
534 }
535
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)536 bool FrontendDelegateImpl::FireSyncEvent(
537 const std::string& eventId, const std::string& param, const std::string& jsonArgs)
538 {
539 std::string resultStr;
540 FireSyncEvent(eventId, param, jsonArgs, resultStr);
541 return (resultStr == "true");
542 }
543
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs,std::string & result)544 void FrontendDelegateImpl::FireSyncEvent(
545 const std::string& eventId, const std::string& param, const std::string& jsonArgs, std::string& result)
546 {
547 int32_t callbackId = callbackCnt_++;
548 std::string args = param;
549 args.append("{\"_callbackId\":\"").append(std::to_string(callbackId)).append("\"}").append(",null");
550 if (!jsonArgs.empty()) {
551 args.append(",").append(jsonArgs); // method args
552 }
553 taskExecutor_->PostSyncTask(
554 [weak = AceType::WeakClaim(this), eventId, args = std::move(args), callbackId, &result] {
555 auto delegate = weak.Upgrade();
556 if (delegate) {
557 delegate->syncEvent_(eventId, args);
558 result = delegate->jsCallBackResult_[callbackId];
559 LOGD("FireSyncEvent eventId: %{public}s, callbackId: %{public}d", eventId.c_str(), callbackId);
560 delegate->jsCallBackResult_.erase(callbackId);
561 }
562 },
563 TaskExecutor::TaskType::JS, "ArkUIFireSyncEvent");
564 }
565
FireExternalEvent(const std::string & eventId,const std::string & componentId,const uint32_t nodeId,const bool isDestroy)566 void FrontendDelegateImpl::FireExternalEvent(
567 const std::string& eventId, const std::string& componentId, const uint32_t nodeId, const bool isDestroy)
568 {
569 taskExecutor_->PostSyncTask(
570 [weak = AceType::WeakClaim(this), componentId, nodeId, isDestroy] {
571 auto delegate = weak.Upgrade();
572 if (delegate) {
573 delegate->externalEvent_(componentId, nodeId, isDestroy);
574 }
575 },
576 TaskExecutor::TaskType::JS, "ArkUIFireExternalEvent");
577 }
578
FireAccessibilityEvent(const AccessibilityEvent & accessibilityEvent)579 void FrontendDelegateImpl::FireAccessibilityEvent(const AccessibilityEvent& accessibilityEvent)
580 {
581 jsAccessibilityManager_->SendAccessibilityAsyncEvent(accessibilityEvent);
582 }
583
InitializeAccessibilityCallback()584 void FrontendDelegateImpl::InitializeAccessibilityCallback()
585 {
586 jsAccessibilityManager_->InitializeCallback();
587 }
588
589 // Start FrontendDelegate overrides.
Push(const std::string & uri,const std::string & params)590 void FrontendDelegateImpl::Push(const std::string& uri, const std::string& params)
591 {
592 Push(uri, params, nullptr);
593 }
594
PushWithCallback(const std::string & uri,const std::string & params,bool recoverable,const std::function<void (const std::string &,int32_t)> & errorCallback,uint32_t routerMode)595 void FrontendDelegateImpl::PushWithCallback(const std::string& uri, const std::string& params, bool recoverable,
596 const std::function<void(const std::string&, int32_t)>& errorCallback, uint32_t routerMode)
597 {
598 Push(uri, params, errorCallback);
599 }
600
Push(const std::string & uri,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback)601 void FrontendDelegateImpl::Push(const std::string& uri, const std::string& params,
602 const std::function<void(const std::string&, int32_t)>& errorCallback)
603 {
604 if (uri.empty()) {
605 LOGE("router.Push uri is empty");
606 return;
607 }
608 if (isRouteStackFull_) {
609 LOGE("the router stack has reached its max size, you can't push any more pages.");
610 EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, uri);
611 if (errorCallback != nullptr) {
612 errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
613 }
614 return;
615 }
616 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(uri);
617 if (!pagePath.empty()) {
618 isPagePathInvalid_ = true;
619 LoadPage(GenerateNextPageId(), pagePath, false, params);
620 if (errorCallback != nullptr) {
621 errorCallback("", ERROR_CODE_NO_ERROR);
622 }
623 } else {
624 isPagePathInvalid_ = false;
625 LOGW("[Engine Log] this uri not support in route push.");
626 if (errorCallback != nullptr) {
627 errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR);
628 }
629 }
630
631 if (taskExecutor_) {
632 taskExecutor_->PostTask(
633 [context = pipelineContextHolder_.Get(), isPagePathInvalid = isPagePathInvalid_]() {
634 if (context) {
635 context->NotifyIsPagePathInvalidDismiss(isPagePathInvalid);
636 }
637 },
638 TaskExecutor::TaskType::UI, "ArkUINotifyIsPagePathInvalidDismiss");
639 }
640 }
641
Replace(const std::string & uri,const std::string & params)642 void FrontendDelegateImpl::Replace(const std::string& uri, const std::string& params)
643 {
644 Replace(uri, params, nullptr);
645 }
646
ReplaceWithCallback(const std::string & uri,const std::string & params,bool recoverable,const std::function<void (const std::string &,int32_t)> & errorCallback,uint32_t routerMode)647 void FrontendDelegateImpl::ReplaceWithCallback(const std::string& uri, const std::string& params, bool recoverable,
648 const std::function<void(const std::string&, int32_t)>& errorCallback, uint32_t routerMode)
649 {
650 Push(uri, params, errorCallback);
651 }
652
Replace(const std::string & uri,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback)653 void FrontendDelegateImpl::Replace(const std::string& uri, const std::string& params,
654 const std::function<void(const std::string&, int32_t)>& errorCallback)
655 {
656 if (uri.empty()) {
657 LOGE("router.Replace uri is empty");
658 return;
659 }
660
661 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(uri);
662 if (!pagePath.empty()) {
663 LoadReplacePage(GenerateNextPageId(), pagePath, params);
664 if (errorCallback != nullptr) {
665 errorCallback("", ERROR_CODE_NO_ERROR);
666 }
667 } else {
668 LOGW("[Engine Log] this uri not support in route replace.");
669 if (errorCallback != nullptr) {
670 errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR_LITE);
671 }
672 }
673 }
674
Back(const std::string & uri,const std::string & params)675 void FrontendDelegateImpl::Back(const std::string& uri, const std::string& params)
676 {
677 auto pipelineContext = pipelineContextHolder_.Get();
678 {
679 std::lock_guard<std::mutex> lock(mutex_);
680 auto& currentPage = pageRouteStack_.back();
681 if (!pageRouteStack_.empty() && currentPage.alertCallback) {
682 backUri_ = uri;
683 backParam_ = params;
684 taskExecutor_->PostTask(
685 [context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get()),
686 dialogProperties = pageRouteStack_.back().dialogProperties,
687 isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
688 if (context) {
689 context->ShowDialog(dialogProperties, isRightToLeft);
690 }
691 },
692 TaskExecutor::TaskType::UI, "ArkUIShowDialogBeforeBack");
693 return;
694 }
695 }
696 BackImplement(uri, params);
697 }
698
BackImplement(const std::string & uri,const std::string & params)699 void FrontendDelegateImpl::BackImplement(const std::string& uri, const std::string& params)
700 {
701 if (uri.empty()) {
702 PopPage();
703 } else {
704 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(uri);
705 pageId_ = GetPageIdByUrl(pagePath);
706 if (!pagePath.empty()) {
707 if (!params.empty()) {
708 std::lock_guard<std::mutex> lock(mutex_);
709 pageParamMap_[pageId_] = params;
710 }
711 PopToPage(pagePath);
712 } else {
713 LOGW("[Engine Log] this uri not support in route Back.");
714 }
715 }
716
717 taskExecutor_->PostTask(
718 [context = pipelineContextHolder_.Get()]() {
719 if (context) {
720 context->NotifyRouterBackDismiss();
721 }
722 },
723 TaskExecutor::TaskType::UI, "ArkUINotifyRouterBackDismiss");
724 }
725
PostponePageTransition()726 void FrontendDelegateImpl::PostponePageTransition()
727 {
728 std::lock_guard<std::mutex> lock(mutex_);
729 taskExecutor_->PostTask(
730 [context = pipelineContextHolder_.Get()]() {
731 if (context) {
732 context->PostponePageTransition();
733 }
734 },
735 TaskExecutor::TaskType::UI, "ArkUIPostponePageTransition");
736 }
737
LaunchPageTransition()738 void FrontendDelegateImpl::LaunchPageTransition()
739 {
740 std::lock_guard<std::mutex> lock(mutex_);
741 taskExecutor_->PostTask(
742 [context = pipelineContextHolder_.Get()]() {
743 if (context) {
744 context->LaunchPageTransition();
745 }
746 },
747 TaskExecutor::TaskType::UI, "ArkUILaunchPageTransition");
748 }
749
Clear()750 void FrontendDelegateImpl::Clear()
751 {
752 ClearInvisiblePages();
753 }
754
GetStackSize() const755 int32_t FrontendDelegateImpl::GetStackSize() const
756 {
757 std::lock_guard<std::mutex> lock(mutex_);
758 return static_cast<int32_t>(pageRouteStack_.size());
759 }
760
GetState(int32_t & index,std::string & name,std::string & path)761 void FrontendDelegateImpl::GetState(int32_t& index, std::string& name, std::string& path)
762 {
763 std::string url;
764 {
765 std::lock_guard<std::mutex> lock(mutex_);
766 if (pageRouteStack_.empty()) {
767 return;
768 }
769 index = static_cast<int32_t>(pageRouteStack_.size());
770 url = pageRouteStack_.back().url;
771 }
772 auto pos = url.rfind(".js");
773 // url length - (.js) length
774 if (pos == url.length() - 3) {
775 url = url.substr(0, pos);
776 }
777 pos = url.rfind("/");
778 if (pos != std::string::npos) {
779 name = url.substr(pos + 1);
780 path = url.substr(0, pos + 1);
781 }
782 }
783
GetComponentsCount()784 size_t FrontendDelegateImpl::GetComponentsCount()
785 {
786 std::lock_guard<std::mutex> lock(mutex_);
787 if (pageRouteStack_.empty()) {
788 return 0;
789 }
790 auto itPage = pageMap_.find(pageRouteStack_.back().pageId);
791 if (itPage == pageMap_.end()) {
792 return 0;
793 }
794 auto domDoc = itPage->second->GetDomDocument();
795 if (!domDoc) {
796 return 0;
797 }
798 return domDoc->GetComponentsCount();
799 }
800
GetParams()801 std::string FrontendDelegateImpl::GetParams()
802 {
803 auto iter = pageParamMap_.find(pageId_);
804 if (iter != pageParamMap_.end()) {
805 return iter->second;
806 } else {
807 return "";
808 }
809 }
810
TriggerPageUpdate(int32_t pageId,bool directExecute)811 void FrontendDelegateImpl::TriggerPageUpdate(int32_t pageId, bool directExecute)
812 {
813 auto page = GetPage(pageId);
814 if (!page) {
815 return;
816 }
817
818 auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
819 ACE_DCHECK(jsPage);
820
821 // Pop all JS command and execute them in UI thread.
822 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
823 jsPage->PopAllCommands(*jsCommands);
824
825 auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
826 WeakPtr<Framework::JsAcePage> jsPageWeak(jsPage);
827 WeakPtr<PipelineContext> contextWeak(pipelineContext);
828 auto updateTask = [weak = AceType::WeakClaim(this), jsPageWeak, contextWeak, jsCommands] {
829 ACE_SCOPED_TRACE("FlushUpdateCommands");
830 auto delegate = weak.Upgrade();
831 auto jsPage = jsPageWeak.Upgrade();
832 auto context = contextWeak.Upgrade();
833 if (!delegate || !jsPage || !context) {
834 LOGE("Page update failed. page or context is null.");
835 EventReport::SendPageRouterException(PageRouterExcepType::UPDATE_PAGE_ERR);
836 return;
837 }
838 bool useLiteStyle = delegate->GetMinPlatformVersion() < COMPATIBLE_VERSION && delegate->IsUseLiteStyle();
839 context->SetUseLiteStyle(useLiteStyle);
840 jsPage->SetUseLiteStyle(useLiteStyle);
841 jsPage->SetUseBoxWrap(delegate->GetMinPlatformVersion() >= WEB_FEATURE_VERSION);
842 // Flush all JS commands.
843 for (const auto& command : *jsCommands) {
844 command->Execute(jsPage);
845 }
846 if (jsPage->GetDomDocument()) {
847 jsPage->GetDomDocument()->HandleComponentPostBinding();
848 }
849 auto accessibilityManager = context->GetAccessibilityManager();
850 if (accessibilityManager) {
851 accessibilityManager->HandleComponentPostBinding();
852 }
853
854 jsPage->ClearShowCommand();
855 std::vector<NodeId> dirtyNodes;
856 jsPage->PopAllDirtyNodes(dirtyNodes);
857 for (auto nodeId : dirtyNodes) {
858 auto patchComponent = jsPage->BuildPagePatch(nodeId);
859 if (patchComponent) {
860 context->ScheduleUpdate(patchComponent);
861 }
862 }
863 };
864 auto weakContext = AceType::WeakClaim(AceType::RawPtr(pipelineContext));
865 taskExecutor_->PostTask(
866 [updateTask, weakContext, directExecute]() {
867 auto pipelineContext = weakContext.Upgrade();
868 if (pipelineContext) {
869 pipelineContext->AddPageUpdateTask(std::move(updateTask), directExecute);
870 }
871 },
872 TaskExecutor::TaskType::UI, "ArkUIAddPageUpdateTask");
873 }
874
PostJsTask(std::function<void ()> && task,const std::string & name)875 void FrontendDelegateImpl::PostJsTask(std::function<void()>&& task, const std::string& name)
876 {
877 taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS, name);
878 }
879
PostUITask(std::function<void ()> && task,const std::string & name)880 void FrontendDelegateImpl::PostUITask(std::function<void()>&& task, const std::string& name)
881 {
882 taskExecutor_->PostTask(task, TaskExecutor::TaskType::UI, name);
883 }
884
GetAppID() const885 const std::string& FrontendDelegateImpl::GetAppID() const
886 {
887 return manifestParser_->GetAppInfo()->GetAppID();
888 }
889
GetAppName() const890 const std::string& FrontendDelegateImpl::GetAppName() const
891 {
892 return manifestParser_->GetAppInfo()->GetAppName();
893 }
894
GetVersionName() const895 const std::string& FrontendDelegateImpl::GetVersionName() const
896 {
897 return manifestParser_->GetAppInfo()->GetVersionName();
898 }
899
GetVersionCode() const900 int32_t FrontendDelegateImpl::GetVersionCode() const
901 {
902 return manifestParser_->GetAppInfo()->GetVersionCode();
903 }
904
GetWindowConfig()905 WindowConfig& FrontendDelegateImpl::GetWindowConfig()
906 {
907 ParseManifest();
908 return manifestParser_->GetWindowConfig();
909 }
910
GetMinPlatformVersion()911 int32_t FrontendDelegateImpl::GetMinPlatformVersion()
912 {
913 ParseManifest();
914 return manifestParser_->GetMinPlatformVersion();
915 }
916
IsUseLiteStyle()917 bool FrontendDelegateImpl::IsUseLiteStyle()
918 {
919 ParseManifest();
920 return manifestParser_->IsUseLiteStyle();
921 }
922
IsWebFeature()923 bool FrontendDelegateImpl::IsWebFeature()
924 {
925 ParseManifest();
926 return manifestParser_->IsWebFeature();
927 }
928
MeasureText(MeasureContext context)929 double FrontendDelegateImpl::MeasureText(MeasureContext context)
930 {
931 if (context.isFontSizeUseDefaultUnit && context.fontSize.has_value() &&
932 !AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
933 context.fontSize = Dimension(context.fontSize->Value(), DimensionUnit::VP);
934 }
935 return MeasureUtil::MeasureText(context);
936 }
937
MeasureTextSize(MeasureContext context)938 Size FrontendDelegateImpl::MeasureTextSize(MeasureContext context)
939 {
940 if (context.isFontSizeUseDefaultUnit && context.fontSize.has_value() &&
941 !AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
942 context.fontSize = Dimension(context.fontSize->Value(), DimensionUnit::VP);
943 }
944 return MeasureUtil::MeasureTextSize(context);
945 }
946
ShowToast(const NG::ToastInfo & toastInfo,std::function<void (int32_t)> && callback)947 void FrontendDelegateImpl::ShowToast(const NG::ToastInfo& toastInfo, std::function<void(int32_t)>&& callback)
948 {
949 NG::ToastInfo updatedToastInfo = toastInfo;
950 updatedToastInfo.duration = std::clamp(toastInfo.duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
951 updatedToastInfo.isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
952 auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
953 auto weak = AceType::WeakClaim(AceType::RawPtr(pipelineContext));
954 taskExecutor_->PostTask(
955 [updatedToastInfo, weak] {
956 ToastComponent::GetInstance().Show(weak.Upgrade(), updatedToastInfo.message, updatedToastInfo.duration,
957 updatedToastInfo.bottom, updatedToastInfo.isRightToLeft);
958 },
959 TaskExecutor::TaskType::UI, "ArkUIShowToast");
960 }
961
GetBoundingRectData(NodeId nodeId)962 Rect FrontendDelegateImpl::GetBoundingRectData(NodeId nodeId)
963 {
964 Rect rect;
965 auto task = [context = pipelineContextHolder_.Get(), nodeId, &rect]() {
966 context->GetBoundingRectData(nodeId, rect);
967 };
968 PostSyncTaskToPage(task, "ArkUIGetBoundingRectData");
969 return rect;
970 }
971
GetInspector(NodeId nodeId)972 std::string FrontendDelegateImpl::GetInspector(NodeId nodeId)
973 {
974 std::string attrs;
975 auto task = [weak = WeakClaim(AceType::RawPtr(jsAccessibilityManager_)), nodeId, &attrs]() {
976 auto accessibilityNodeManager = weak.Upgrade();
977 if (accessibilityNodeManager) {
978 attrs = accessibilityNodeManager->GetInspectorNodeById(nodeId);
979 }
980 };
981 PostSyncTaskToPage(task, "ArkUIGetInspectorNode");
982 return attrs;
983 }
984
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)985 void FrontendDelegateImpl::ShowDialog(const std::string& title, const std::string& message,
986 const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
987 const std::set<std::string>& callbacks)
988 {
989 if (!taskExecutor_) {
990 LOGE("task executor is null.");
991 return;
992 }
993 std::unordered_map<std::string, EventMarker> callbackMarkers;
994 if (callbacks.find(COMMON_SUCCESS) != callbacks.end()) {
995 auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
996 BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
997 successEventMarker, [callback, taskExecutor = taskExecutor_](int32_t successType) {
998 taskExecutor->PostTask([callback, successType]() { callback(0, successType); },
999 TaskExecutor::TaskType::JS, "ArkUIShowDialogSuccessCallback");
1000 });
1001 callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1002 }
1003 if (callbacks.find(COMMON_CANCEL) != callbacks.end()) {
1004 auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1005 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1006 cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
1007 taskExecutor->PostTask(
1008 [callback]() { callback(1, 0); }, TaskExecutor::TaskType::JS, "ArkUIShowDialogCancelCallback");
1009 });
1010 callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
1011 }
1012 if (callbacks.find(COMMON_COMPLETE) != callbacks.end()) {
1013 auto completeEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1014 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1015 completeEventMarker, [callback, taskExecutor = taskExecutor_] {
1016 taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_COMPLETE, 0); },
1017 TaskExecutor::TaskType::JS, "ArkUIShowDialogCompleteCallback");
1018 });
1019 callbackMarkers.emplace(COMMON_COMPLETE, completeEventMarker);
1020 }
1021 DialogProperties dialogProperties = {
1022 .title = title,
1023 .content = message,
1024 .autoCancel = autoCancel,
1025 .buttons = buttons,
1026 .callbacks = std::move(callbackMarkers),
1027 };
1028 WeakPtr<PipelineContext> weak = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1029 taskExecutor_->PostTask(
1030 [weak, dialogProperties, isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
1031 auto context = weak.Upgrade();
1032 if (context) {
1033 context->ShowDialog(dialogProperties, isRightToLeft);
1034 }
1035 },
1036 TaskExecutor::TaskType::UI, "ArkUIShowDialog");
1037 }
1038
ShowDialog(const PromptDialogAttr & dialogAttr,const std::vector<ButtonInfo> & buttons,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)1039 void FrontendDelegateImpl::ShowDialog(const PromptDialogAttr& dialogAttr, const std::vector<ButtonInfo>& buttons,
1040 std::function<void(int32_t, int32_t)>&& callback, const std::set<std::string>& callbacks)
1041 {
1042 ShowDialog(dialogAttr.title, dialogAttr.message, buttons, dialogAttr.autoCancel, std::move(callback), callbacks);
1043 }
1044
ShowActionMenu(const std::string & title,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)1045 void FrontendDelegateImpl::ShowActionMenu(const std::string& title,
1046 const std::vector<ButtonInfo>& button, std::function<void(int32_t, int32_t)>&& callback)
1047 {
1048 if (!taskExecutor_) {
1049 return;
1050 }
1051
1052 std::unordered_map<std::string, EventMarker> callbackMarkers;
1053
1054 auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
1055 BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
1056 successEventMarker, [callback, number = button.size(), taskExecutor = taskExecutor_](int32_t successType) {
1057 taskExecutor->PostTask(
1058 [callback, number, successType]() {
1059 // if callback index is larger than button's number, cancel button is selected
1060 if (static_cast<size_t>(successType) == number) {
1061 callback(1, 0);
1062 } else {
1063 callback(0, successType);
1064 }
1065 },
1066 TaskExecutor::TaskType::JS, "ArkUIShowActionMenuSuccess");
1067 });
1068 callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1069
1070 auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1071 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1072 cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
1073 taskExecutor->PostTask([callback]() { callback(1, 0); },
1074 TaskExecutor::TaskType::JS, "ArkUIShowActionMenuCancel");
1075 });
1076 callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
1077
1078 DialogProperties dialogProperties = {
1079 .title = title,
1080 .autoCancel = true,
1081 .isMenu = true,
1082 .buttons = button,
1083 .callbacks = std::move(callbackMarkers),
1084 };
1085 ButtonInfo buttonInfo = {
1086 .text = Localization::GetInstance()->GetEntryLetters("common.cancel"),
1087 .textColor = "#000000"
1088 };
1089 dialogProperties.buttons.emplace_back(buttonInfo);
1090 WeakPtr<PipelineContext> weak = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1091 taskExecutor_->PostTask(
1092 [weak, dialogProperties, isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
1093 auto context = weak.Upgrade();
1094 if (context) {
1095 context->ShowDialog(dialogProperties, isRightToLeft);
1096 }
1097 },
1098 TaskExecutor::TaskType::UI, "ArkUIShowActionMenu");
1099 }
1100
ShowActionMenu(const PromptDialogAttr & dialogAttr,const std::vector<ButtonInfo> & buttons,std::function<void (int32_t,int32_t)> && callback)1101 void FrontendDelegateImpl::ShowActionMenu(const PromptDialogAttr& dialogAttr, const std::vector<ButtonInfo>& buttons,
1102 std::function<void(int32_t, int32_t)>&& callback)
1103 {
1104 ShowActionMenu(dialogAttr.title, buttons, std::move(callback));
1105 }
1106
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)1107 void FrontendDelegateImpl::EnableAlertBeforeBackPage(
1108 const std::string& message, std::function<void(int32_t)>&& callback)
1109 {
1110 if (!taskExecutor_) {
1111 LOGE("task executor is null.");
1112 return;
1113 }
1114
1115 std::unordered_map<std::string, EventMarker> callbackMarkers;
1116 auto pipelineContext = pipelineContextHolder_.Get();
1117 auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
1118 BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(successEventMarker,
1119 [weak = AceType::WeakClaim(this), callback, taskExecutor = taskExecutor_](int32_t successType) {
1120 taskExecutor->PostTask(
1121 [weak, callback, successType]() {
1122 callback(successType);
1123 if (!successType) {
1124 return;
1125 }
1126 auto delegate = weak.Upgrade();
1127 if (!delegate) {
1128 return;
1129 }
1130 delegate->BackImplement(delegate->backUri_, delegate->backParam_);
1131 },
1132 TaskExecutor::TaskType::JS, "ArkUIBackPageSuccessEvent");
1133 });
1134 callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1135
1136 std::lock_guard<std::mutex> lock(mutex_);
1137 if (pageRouteStack_.empty()) {
1138 return;
1139 }
1140
1141 auto& currentPage = pageRouteStack_.back();
1142 ClearAlertCallback(currentPage);
1143 currentPage.dialogProperties = {
1144 .content = message,
1145 .autoCancel = false,
1146 .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
1147 { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
1148 .callbacks = std::move(callbackMarkers),
1149 };
1150 }
1151
DisableAlertBeforeBackPage()1152 void FrontendDelegateImpl::DisableAlertBeforeBackPage()
1153 {
1154 std::lock_guard<std::mutex> lock(mutex_);
1155 if (pageRouteStack_.empty()) {
1156 LOGE("page stack is null.");
1157 return;
1158 }
1159 auto& currentPage = pageRouteStack_.back();
1160 ClearAlertCallback(currentPage);
1161 }
1162
SetCallBackResult(const std::string & callBackId,const std::string & result)1163 void FrontendDelegateImpl::SetCallBackResult(const std::string& callBackId, const std::string& result)
1164 {
1165 jsCallBackResult_.try_emplace(StringToInt(callBackId), result);
1166 }
1167
WaitTimer(const std::string & callbackId,const std::string & delay,bool isInterval,bool isFirst)1168 void FrontendDelegateImpl::WaitTimer(
1169 const std::string& callbackId, const std::string& delay, bool isInterval, bool isFirst)
1170 {
1171 if (!isFirst) {
1172 auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1173 // If not find the callbackId in map, means this timer already was removed,
1174 // no need create a new cancelableTimer again.
1175 if (timeoutTaskIter == timeoutTaskMap_.end()) {
1176 return;
1177 }
1178 }
1179
1180 int32_t delayTime = StringToInt(delay);
1181 // CancelableCallback class can only be executed once.
1182 CancelableCallback<void()> cancelableTimer;
1183 cancelableTimer.Reset([callbackId, delay, isInterval, call = timer_] { call(callbackId, delay, isInterval); });
1184 auto result = timeoutTaskMap_.try_emplace(callbackId, cancelableTimer);
1185 if (!result.second) {
1186 result.first->second = cancelableTimer;
1187 }
1188 taskExecutor_->PostDelayedTask(cancelableTimer, TaskExecutor::TaskType::JS, delayTime, "ArkUICancelableTimer");
1189 }
1190
ClearTimer(const std::string & callbackId)1191 void FrontendDelegateImpl::ClearTimer(const std::string& callbackId)
1192 {
1193 auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1194 if (timeoutTaskIter != timeoutTaskMap_.end()) {
1195 timeoutTaskIter->second.Cancel();
1196 timeoutTaskMap_.erase(timeoutTaskIter);
1197 } else {
1198 LOGW("ClearTimer callbackId not found");
1199 }
1200 }
1201
PostSyncTaskToPage(std::function<void ()> && task,const std::string & name)1202 void FrontendDelegateImpl::PostSyncTaskToPage(std::function<void()>&& task, const std::string& name)
1203 {
1204 pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
1205 TriggerPageUpdate(GetRunningPageId(), true);
1206 taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::UI, name);
1207 }
1208
AddTaskObserver(std::function<void ()> && task)1209 void FrontendDelegateImpl::AddTaskObserver(std::function<void()>&& task)
1210 {
1211 taskExecutor_->AddTaskObserver(std::move(task));
1212 }
1213
RemoveTaskObserver()1214 void FrontendDelegateImpl::RemoveTaskObserver()
1215 {
1216 taskExecutor_->RemoveTaskObserver();
1217 }
1218
GetAssetContent(const std::string & url,std::string & content)1219 bool FrontendDelegateImpl::GetAssetContent(const std::string& url, std::string& content)
1220 {
1221 return GetAssetContentImpl(assetManager_, url, content);
1222 }
1223
GetAssetContent(const std::string & url,std::vector<uint8_t> & content)1224 bool FrontendDelegateImpl::GetAssetContent(const std::string& url, std::vector<uint8_t>& content)
1225 {
1226 return GetAssetContentImpl(assetManager_, url, content);
1227 }
1228
GetAssetPath(const std::string & url)1229 std::string FrontendDelegateImpl::GetAssetPath(const std::string& url)
1230 {
1231 return GetAssetPathImpl(assetManager_, url);
1232 }
1233
LoadPage(int32_t pageId,const std::string & url,bool isMainPage,const std::string & params)1234 UIContentErrorCode FrontendDelegateImpl::LoadPage(
1235 int32_t pageId, const std::string& url, bool isMainPage, const std::string& params)
1236 {
1237 {
1238 std::lock_guard<std::mutex> lock(mutex_);
1239 pageId_ = pageId;
1240 pageParamMap_[pageId] = params;
1241 }
1242 if (pageId == INVALID_PAGE_ID) {
1243 LOGE("FrontendDelegateImpl, invalid page id");
1244 EventReport::SendPageRouterException(PageRouterExcepType::LOAD_PAGE_ERR, url);
1245 return UIContentErrorCode::INVALID_PAGE_ID;
1246 }
1247 if (isStagingPageExist_) {
1248 LOGE("FrontendDelegateImpl, load page failed, waiting for current page loading finish.");
1249 RecyclePageId(pageId);
1250 return UIContentErrorCode::STAGING_PAGE_EXIST;
1251 }
1252 isStagingPageExist_ = true;
1253 auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1254 auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, url);
1255 page->SetPageParams(params);
1256 page->SetFlushCallback([weak = AceType::WeakClaim(this), isMainPage](const RefPtr<JsAcePage>& acePage) {
1257 auto delegate = weak.Upgrade();
1258 if (delegate && acePage) {
1259 delegate->FlushPageCommand(acePage, acePage->GetUrl(), isMainPage);
1260 }
1261 });
1262 taskExecutor_->PostTask(
1263 [weak = AceType::WeakClaim(this), page, url, isMainPage] {
1264 auto delegate = weak.Upgrade();
1265 if (!delegate) {
1266 LOGE("the delegate context is nullptr");
1267 return;
1268 }
1269 delegate->loadJs_(url, page, isMainPage);
1270 page->FlushCommands();
1271 // just make sure the pipelineContext is created.
1272 auto pipelineContext = delegate->pipelineContextHolder_.Get();
1273 if (!pipelineContext) {
1274 LOGE("the pipeline context is nullptr");
1275 return;
1276 }
1277 if (delegate->GetMinPlatformVersion() > 0) {
1278 pipelineContext->SetMinPlatformVersion(delegate->GetMinPlatformVersion());
1279 }
1280 delegate->taskExecutor_->PostTask(
1281 [weak, page] {
1282 auto delegate = weak.Upgrade();
1283 if (delegate && delegate->pipelineContextHolder_.Get()) {
1284 auto context = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1285 if (context) {
1286 context->FlushFocus();
1287 }
1288 }
1289 if (page->GetDomDocument()) {
1290 page->GetDomDocument()->HandlePageLoadFinish();
1291 }
1292 },
1293 TaskExecutor::TaskType::UI, "ArkUIPageLoadFinish");
1294 },
1295 TaskExecutor::TaskType::JS, "ArkUILoadJsPage");
1296
1297 return UIContentErrorCode::NO_ERRORS;
1298 }
1299
OnSurfaceChanged()1300 void FrontendDelegateImpl::OnSurfaceChanged()
1301 {
1302 if (mediaQueryInfo_->GetIsInit()) {
1303 mediaQueryInfo_->SetIsInit(false);
1304 }
1305 mediaQueryInfo_->EnsureListenerIdValid();
1306 OnMediaQueryUpdate();
1307 }
1308
OnLayoutCompleted(const std::string & componentId)1309 void FrontendDelegateImpl::OnLayoutCompleted(const std::string& componentId) {}
1310
OnDrawCompleted(const std::string & componentId)1311 void FrontendDelegateImpl::OnDrawCompleted(const std::string& componentId) {}
1312
OnMediaQueryUpdate(bool isSynchronous)1313 void FrontendDelegateImpl::OnMediaQueryUpdate(bool isSynchronous)
1314 {
1315 if (mediaQueryInfo_->GetIsInit()) {
1316 return;
1317 }
1318
1319 taskExecutor_->PostTask(
1320 [weak = AceType::WeakClaim(this)] {
1321 auto delegate = weak.Upgrade();
1322 if (!delegate) {
1323 return;
1324 }
1325 const auto& info = delegate->mediaQueryInfo_->GetMediaQueryInfo();
1326 // request css mediaquery
1327 std::string param("\"viewsizechanged\",");
1328 param.append(info);
1329 delegate->asyncEvent_("_root", param);
1330
1331 // request js mediaquery
1332 const auto& listenerId = delegate->mediaQueryInfo_->GetListenerId();
1333 delegate->mediaQueryCallback_(listenerId, info);
1334 delegate->mediaQueryInfo_->ResetListenerId();
1335 },
1336 TaskExecutor::TaskType::JS, "ArkUIMediaQueryUpdate");
1337 }
1338
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1339 void FrontendDelegateImpl::OnPageReady(const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1340 {
1341 LOGI("OnPageReady url = %{private}s", url.c_str());
1342 // Pop all JS command and execute them in UI thread.
1343 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1344 page->PopAllCommands(*jsCommands);
1345
1346 auto pipelineContext = pipelineContextHolder_.Get();
1347 page->SetPipelineContext(pipelineContext);
1348 taskExecutor_->PostTask(
1349 [weak = AceType::WeakClaim(this), page, url, jsCommands, isMainPage] {
1350 auto delegate = weak.Upgrade();
1351 if (!delegate) {
1352 return;
1353 }
1354 delegate->SetCurrentReadyPage(page);
1355 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1356 CHECK_NULL_VOID(pipelineContext);
1357 bool useLiteStyle = delegate->GetMinPlatformVersion() < COMPATIBLE_VERSION && delegate->IsUseLiteStyle();
1358 pipelineContext->SetUseLiteStyle(useLiteStyle);
1359 page->SetUseLiteStyle(useLiteStyle);
1360 page->SetUseBoxWrap(delegate->GetMinPlatformVersion() >= WEB_FEATURE_VERSION);
1361 // Flush all JS commands.
1362 for (const auto& command : *jsCommands) {
1363 command->Execute(page);
1364 }
1365 // Just clear all dirty nodes.
1366 page->ClearAllDirtyNodes();
1367 if (page->GetDomDocument()) {
1368 page->GetDomDocument()->HandleComponentPostBinding();
1369 }
1370 if (pipelineContext->GetAccessibilityManager()) {
1371 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1372 }
1373 if (pipelineContext->CanPushPage()) {
1374 if (!isMainPage) {
1375 delegate->OnPageHide();
1376 }
1377 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1378 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1379 [weak, page](
1380 const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1381 auto delegate = weak.Upgrade();
1382 if (delegate) {
1383 delegate->PushPageTransitionListener(event, page);
1384 }
1385 });
1386 pipelineContext->PushPage(page->BuildPage(url));
1387 delegate->OnPushPageSuccess(page, url);
1388 delegate->SetCurrentPage(page->GetPageId());
1389 delegate->OnMediaQueryUpdate();
1390 } else {
1391 // This page has been loaded but become useless now, the corresponding js instance
1392 // must be destroyed to avoid memory leak.
1393 delegate->OnPageDestroy(page->GetPageId());
1394 delegate->ResetStagingPage();
1395 }
1396 delegate->isStagingPageExist_ = false;
1397 },
1398 TaskExecutor::TaskType::UI, "ArkUIPageReady");
1399 }
1400
PushPageTransitionListener(const TransitionEvent & event,const RefPtr<JsAcePage> & page)1401 void FrontendDelegateImpl::PushPageTransitionListener(
1402 const TransitionEvent& event, const RefPtr<JsAcePage>& page)
1403 {
1404 if (event == TransitionEvent::PUSH_END) {
1405 OnPageShow();
1406 }
1407 }
1408
FlushPageCommand(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1409 void FrontendDelegateImpl::FlushPageCommand(const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1410 {
1411 if (!page) {
1412 return;
1413 }
1414 LOGI("FlushPageCommand FragmentCount(%{public}d)", page->FragmentCount());
1415 if (page->FragmentCount() == 1) {
1416 OnPageReady(page, url, isMainPage);
1417 } else {
1418 TriggerPageUpdate(page->GetPageId());
1419 }
1420 }
1421
AddPageLocked(const RefPtr<JsAcePage> & page)1422 void FrontendDelegateImpl::AddPageLocked(const RefPtr<JsAcePage>& page)
1423 {
1424 auto result = pageMap_.try_emplace(page->GetPageId(), page);
1425 if (!result.second) {
1426 LOGW("the page has already in the map");
1427 }
1428 }
1429
SetCurrentPage(int32_t pageId)1430 void FrontendDelegateImpl::SetCurrentPage(int32_t pageId)
1431 {
1432 auto page = GetPage(pageId);
1433 if (page != nullptr) {
1434 jsAccessibilityManager_->SetRunningPage(page);
1435 taskExecutor_->PostTask(
1436 [updatePage = updatePage_, page] { updatePage(page); }, TaskExecutor::TaskType::JS, "ArkUISetCurrentPage");
1437 } else {
1438 LOGE("FrontendDelegateImpl SetCurrentPage page is null.");
1439 }
1440 }
1441
OnPushPageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1442 void FrontendDelegateImpl::OnPushPageSuccess(const RefPtr<JsAcePage>& page, const std::string& url)
1443 {
1444 std::lock_guard<std::mutex> lock(mutex_);
1445 AddPageLocked(page);
1446 PageInfo pageInfo;
1447 pageInfo.pageId = page->GetPageId();
1448 pageInfo.url = url;
1449 pageRouteStack_.emplace_back(pageInfo);
1450 if (pageRouteStack_.size() >= MAX_ROUTER_STACK) {
1451 isRouteStackFull_ = true;
1452 EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, page->GetUrl());
1453 }
1454 auto pipelineContext = pipelineContextHolder_.Get();
1455 if (pipelineContext) {
1456 pipelineContext->onRouterChange(url);
1457 pipelineContext->NotifyPopPageSuccessDismiss(url, pageRouteStack_.back().pageId);
1458 }
1459 LOGI("OnPushPageSuccess size=%{private}zu,pageId=%{private}d,url=%{private}s", pageRouteStack_.size(),
1460 pageRouteStack_.back().pageId, pageRouteStack_.back().url.c_str());
1461 }
1462
OnPopToPageSuccess(const std::string & url)1463 void FrontendDelegateImpl::OnPopToPageSuccess(const std::string& url)
1464 {
1465 std::lock_guard<std::mutex> lock(mutex_);
1466 while (!pageRouteStack_.empty()) {
1467 if (pageRouteStack_.back().url == url) {
1468 break;
1469 }
1470 OnPageDestroy(pageRouteStack_.back().pageId);
1471 pageMap_.erase(pageRouteStack_.back().pageId);
1472 pageParamMap_.erase(pageRouteStack_.back().pageId);
1473 ClearAlertCallback(pageRouteStack_.back());
1474 pageRouteStack_.pop_back();
1475 }
1476 if (isRouteStackFull_) {
1477 isRouteStackFull_ = false;
1478 }
1479 auto pipelineContext = pipelineContextHolder_.Get();
1480 if (pipelineContext) {
1481 pipelineContext->onRouterChange(url);
1482 pipelineContext->NotifyPopPageSuccessDismiss(url, pageRouteStack_.back().pageId);
1483 }
1484 }
1485
PopToPage(const std::string & url)1486 void FrontendDelegateImpl::PopToPage(const std::string& url)
1487 {
1488 taskExecutor_->PostTask(
1489 [weak = AceType::WeakClaim(this), url] {
1490 auto delegate = weak.Upgrade();
1491 if (!delegate) {
1492 return;
1493 }
1494 auto pageId = delegate->GetPageIdByUrl(url);
1495 if (pageId == INVALID_PAGE_ID) {
1496 return;
1497 }
1498 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1499 CHECK_NULL_VOID(pipelineContext);
1500 if (!pipelineContext->CanPopPage()) {
1501 delegate->ResetStagingPage();
1502 return;
1503 }
1504 delegate->OnPageHide();
1505 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1506 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1507 [weak, url, pageId](
1508 const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1509 auto delegate = weak.Upgrade();
1510 if (delegate) {
1511 delegate->PopToPageTransitionListener(event, url, pageId);
1512 }
1513 });
1514 pipelineContext->PopToPage(pageId);
1515 },
1516 TaskExecutor::TaskType::UI, "ArkUIPopToPage");
1517 }
1518
PopToPageTransitionListener(const TransitionEvent & event,const std::string & url,int32_t pageId)1519 void FrontendDelegateImpl::PopToPageTransitionListener(
1520 const TransitionEvent& event, const std::string& url, int32_t pageId)
1521 {
1522 if (event == TransitionEvent::POP_END) {
1523 OnPopToPageSuccess(url);
1524 SetCurrentPage(pageId);
1525 OnPageShow();
1526 OnMediaQueryUpdate();
1527 }
1528 }
1529
OnPopPageSuccess()1530 int32_t FrontendDelegateImpl::OnPopPageSuccess()
1531 {
1532 std::lock_guard<std::mutex> lock(mutex_);
1533 pageMap_.erase(pageRouteStack_.back().pageId);
1534 pageParamMap_.erase(pageRouteStack_.back().pageId);
1535 ClearAlertCallback(pageRouteStack_.back());
1536 pageRouteStack_.pop_back();
1537 if (isRouteStackFull_) {
1538 isRouteStackFull_ = false;
1539 }
1540 if (!pageRouteStack_.empty()) {
1541 auto context = pipelineContextHolder_.Get();
1542 if (context) {
1543 context->NotifyPopPageSuccessDismiss(pageRouteStack_.back().url, pageRouteStack_.back().pageId);
1544 context->onRouterChange(pageRouteStack_.back().url);
1545 }
1546
1547 return pageRouteStack_.back().pageId;
1548 }
1549 return INVALID_PAGE_ID;
1550 }
1551
PopPage()1552 void FrontendDelegateImpl::PopPage()
1553 {
1554 taskExecutor_->PostTask(
1555 [weak = AceType::WeakClaim(this)] {
1556 auto delegate = weak.Upgrade();
1557 if (!delegate) {
1558 return;
1559 }
1560 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1561 CHECK_NULL_VOID(pipelineContext);
1562 if (delegate->GetStackSize() == 1) {
1563 if (delegate->disallowPopLastPage_) {
1564 LOGW("Not allow back because this is the last page!");
1565 return;
1566 }
1567 delegate->OnPageHide();
1568 delegate->OnPageDestroy(delegate->GetRunningPageId());
1569 delegate->OnPopPageSuccess();
1570 pipelineContext->Finish();
1571 return;
1572 }
1573 if (!pipelineContext->CanPopPage()) {
1574 delegate->ResetStagingPage();
1575 return;
1576 }
1577 delegate->OnPageHide();
1578 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1579 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1580 [weak, destroyPageId = delegate->GetRunningPageId()](
1581 const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1582 auto delegate = weak.Upgrade();
1583 if (delegate) {
1584 delegate->PopPageTransitionListener(event, destroyPageId);
1585 }
1586 });
1587 pipelineContext->PopPage();
1588 },
1589 TaskExecutor::TaskType::UI, "ArkUIPopPage");
1590 }
1591
PopPageTransitionListener(const TransitionEvent & event,int32_t destroyPageId)1592 void FrontendDelegateImpl::PopPageTransitionListener(const TransitionEvent& event, int32_t destroyPageId)
1593 {
1594 if (event == TransitionEvent::POP_END) {
1595 OnPageDestroy(destroyPageId);
1596 auto pageId = OnPopPageSuccess();
1597 SetCurrentPage(pageId);
1598 OnPageShow();
1599 OnMediaQueryUpdate();
1600 }
1601 }
1602
OnClearInvisiblePagesSuccess()1603 int32_t FrontendDelegateImpl::OnClearInvisiblePagesSuccess()
1604 {
1605 std::lock_guard<std::mutex> lock(mutex_);
1606 PageInfo pageInfo = std::move(pageRouteStack_.back());
1607 pageRouteStack_.pop_back();
1608 for (const auto& info : pageRouteStack_) {
1609 ClearAlertCallback(info);
1610 OnPageDestroy(info.pageId);
1611 pageMap_.erase(info.pageId);
1612 pageParamMap_.erase(info.pageId);
1613 }
1614 pageRouteStack_.clear();
1615 int32_t resPageId = pageInfo.pageId;
1616 pageRouteStack_.emplace_back(std::move(pageInfo));
1617 if (isRouteStackFull_) {
1618 isRouteStackFull_ = false;
1619 }
1620 return resPageId;
1621 }
1622
ClearInvisiblePages()1623 void FrontendDelegateImpl::ClearInvisiblePages()
1624 {
1625 std::lock_guard<std::mutex> lock(mutex_);
1626 // Execute invisible pages' OnJsEngineDestroy to release JsValue
1627 for (auto pageRouteIter = pageRouteStack_.cbegin(); pageRouteIter != pageRouteStack_.cend() - 1; ++pageRouteIter) {
1628 const auto& info = *pageRouteIter;
1629 auto iter = pageMap_.find(info.pageId);
1630 if (iter != pageMap_.end()) {
1631 auto page = iter->second;
1632 if (page) {
1633 page->OnJsEngineDestroy();
1634 }
1635 }
1636 }
1637
1638 taskExecutor_->PostTask(
1639 [weak = AceType::WeakClaim(this)] {
1640 auto delegate = weak.Upgrade();
1641 if (!delegate) {
1642 return;
1643 }
1644 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1645 CHECK_NULL_VOID(pipelineContext);
1646 if (pipelineContext->ClearInvisiblePages()) {
1647 auto pageId = delegate->OnClearInvisiblePagesSuccess();
1648 delegate->SetCurrentPage(pageId);
1649 }
1650 },
1651 TaskExecutor::TaskType::UI, "ArkUIClearInvisiblePages");
1652 }
1653
OnReplacePageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1654 void FrontendDelegateImpl::OnReplacePageSuccess(const RefPtr<JsAcePage>& page, const std::string& url)
1655 {
1656 if (!page) {
1657 return;
1658 }
1659 std::lock_guard<std::mutex> lock(mutex_);
1660 AddPageLocked(page);
1661 if (!pageRouteStack_.empty()) {
1662 pageMap_.erase(pageRouteStack_.back().pageId);
1663 pageParamMap_.erase(pageRouteStack_.back().pageId);
1664 ClearAlertCallback(pageRouteStack_.back());
1665 pageRouteStack_.pop_back();
1666 }
1667 PageInfo pageInfo;
1668 pageInfo.pageId = page->GetPageId();
1669 pageInfo.url = url;
1670 pageRouteStack_.emplace_back(pageInfo);
1671 auto pipelineContext = pipelineContextHolder_.Get();
1672 if (pipelineContext) {
1673 pipelineContext->onRouterChange(url);
1674 pipelineContext->NotifyPopPageSuccessDismiss(url, pageRouteStack_.back().pageId);
1675 }
1676 }
1677
ReplacePage(const RefPtr<JsAcePage> & page,const std::string & url)1678 void FrontendDelegateImpl::ReplacePage(const RefPtr<JsAcePage>& page, const std::string& url)
1679 {
1680 LOGI("ReplacePage url = %{private}s", url.c_str());
1681 // Pop all JS command and execute them in UI thread.
1682 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1683 page->PopAllCommands(*jsCommands);
1684
1685 auto pipelineContext = pipelineContextHolder_.Get();
1686 page->SetPipelineContext(pipelineContext);
1687 taskExecutor_->PostTask(
1688 [weak = AceType::WeakClaim(this), page, url, jsCommands] {
1689 auto delegate = weak.Upgrade();
1690 if (!delegate) {
1691 return;
1692 }
1693 delegate->SetCurrentReadyPage(page);
1694 auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1695 CHECK_NULL_VOID(pipelineContext);
1696 bool useLiteStyle = delegate->GetMinPlatformVersion() < COMPATIBLE_VERSION && delegate->IsUseLiteStyle();
1697 pipelineContext->SetUseLiteStyle(useLiteStyle);
1698 page->SetUseLiteStyle(useLiteStyle);
1699 page->SetUseBoxWrap(delegate->GetMinPlatformVersion() >= WEB_FEATURE_VERSION);
1700 // Flush all JS commands.
1701 for (const auto& command : *jsCommands) {
1702 command->Execute(page);
1703 }
1704 // Just clear all dirty nodes.
1705 page->ClearAllDirtyNodes();
1706 page->GetDomDocument()->HandleComponentPostBinding();
1707 if (pipelineContext->GetAccessibilityManager()) {
1708 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1709 }
1710 if (pipelineContext->CanReplacePage()) {
1711 delegate->OnPageHide();
1712 delegate->OnPageDestroy(delegate->GetRunningPageId());
1713 pipelineContext->ReplacePage(page->BuildPage(url));
1714 delegate->OnReplacePageSuccess(page, url);
1715 delegate->SetCurrentPage(page->GetPageId());
1716 delegate->OnPageShow();
1717 delegate->OnMediaQueryUpdate();
1718 } else {
1719 // This page has been loaded but become useless now, the corresponding js instance
1720 // must be destroyed to avoid memory leak.
1721 delegate->OnPageDestroy(page->GetPageId());
1722 delegate->ResetStagingPage();
1723 }
1724 delegate->isStagingPageExist_ = false;
1725 },
1726 TaskExecutor::TaskType::UI, "ArkUIReplacePage");
1727 }
1728
LoadReplacePage(int32_t pageId,const std::string & url,const std::string & params)1729 void FrontendDelegateImpl::LoadReplacePage(int32_t pageId, const std::string& url, const std::string& params)
1730 {
1731 {
1732 std::lock_guard<std::mutex> lock(mutex_);
1733 pageId_ = pageId;
1734 pageParamMap_[pageId] = params;
1735 }
1736 if (pageId == INVALID_PAGE_ID) {
1737 LOGE("FrontendDelegateImpl, invalid page id");
1738 EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1739 return;
1740 }
1741 if (isStagingPageExist_) {
1742 LOGE("FrontendDelegateImpl, replace page failed, waiting for current page loading finish.");
1743 EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1744 return;
1745 }
1746 isStagingPageExist_ = true;
1747 auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1748 auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, url);
1749 page->SetPageParams(params);
1750 taskExecutor_->PostTask(
1751 [page, url, weak = AceType::WeakClaim(this)] {
1752 auto delegate = weak.Upgrade();
1753 if (delegate) {
1754 delegate->loadJs_(url, page, false);
1755 delegate->ReplacePage(page, url);
1756 }
1757 },
1758 TaskExecutor::TaskType::JS, "ArkUILoadReplacePage");
1759 }
1760
RebuildAllPages()1761 void FrontendDelegateImpl::RebuildAllPages()
1762 {
1763 std::unordered_map<int32_t, RefPtr<JsAcePage>> pages;
1764 {
1765 std::lock_guard<std::mutex> lock(mutex_);
1766 pages.insert(pageMap_.begin(), pageMap_.end());
1767 }
1768 for (const auto& [pageId, page] : pages) {
1769 taskExecutor_->PostTask(
1770 [weakPage = WeakPtr<JsAcePage>(page)] {
1771 auto page = weakPage.Upgrade();
1772 if (!page) {
1773 return;
1774 }
1775 auto domDoc = page->GetDomDocument();
1776 if (!domDoc) {
1777 return;
1778 }
1779 auto rootNode = domDoc->GetDOMNodeById(domDoc->GetRootNodeId());
1780 if (!rootNode) {
1781 return;
1782 }
1783 rootNode->UpdateStyleWithChildren();
1784 },
1785 TaskExecutor::TaskType::UI, "ArkUIRebuildPage");
1786 }
1787 }
1788
OnPageShow()1789 void FrontendDelegateImpl::OnPageShow()
1790 {
1791 FireAsyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
1792 }
1793
OnPageHide()1794 void FrontendDelegateImpl::OnPageHide()
1795 {
1796 FireAsyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
1797 }
1798
OnConfigurationUpdated(const std::string & configurationData)1799 void FrontendDelegateImpl::OnConfigurationUpdated(const std::string& configurationData)
1800 {
1801 FireSyncEvent("_root", std::string("\"onConfigurationUpdated\","), configurationData);
1802 }
1803
ClearAlertCallback(PageInfo pageInfo)1804 void FrontendDelegateImpl::ClearAlertCallback(PageInfo pageInfo)
1805 {
1806 if (pageInfo.alertCallback) {
1807 // notify to clear js reference
1808 pageInfo.alertCallback(static_cast<int32_t>(AlertState::RECOVERY));
1809 pageInfo.alertCallback = nullptr;
1810 }
1811 }
1812
OnPageDestroy(int32_t pageId)1813 void FrontendDelegateImpl::OnPageDestroy(int32_t pageId)
1814 {
1815 taskExecutor_->PostTask(
1816 [weak = AceType::WeakClaim(this), pageId] {
1817 auto delegate = weak.Upgrade();
1818 if (delegate) {
1819 auto iter = delegate->pageMap_.find(pageId);
1820 if (iter != delegate->pageMap_.end()) {
1821 auto page = iter->second;
1822 if (page) {
1823 page->OnJsEngineDestroy();
1824 }
1825 }
1826 delegate->destroyPage_(pageId);
1827 delegate->RecyclePageId(pageId);
1828 }
1829 },
1830 TaskExecutor::TaskType::JS, "ArkUIPageDestroy");
1831 }
1832
GetRunningPageId() const1833 int32_t FrontendDelegateImpl::GetRunningPageId() const
1834 {
1835 std::lock_guard<std::mutex> lock(mutex_);
1836 if (pageRouteStack_.empty()) {
1837 return INVALID_PAGE_ID;
1838 }
1839 return pageRouteStack_.back().pageId;
1840 }
1841
GetRunningPageUrl() const1842 std::string FrontendDelegateImpl::GetRunningPageUrl() const
1843 {
1844 std::lock_guard<std::mutex> lock(mutex_);
1845 if (pageRouteStack_.empty()) {
1846 return std::string();
1847 }
1848 const auto& pageUrl = pageRouteStack_.back().url;
1849 auto pos = pageUrl.rfind(".js");
1850 // url length - (.js) length
1851 if (pos == pageUrl.length() - 3) {
1852 return pageUrl.substr(0, pos);
1853 }
1854 return pageUrl;
1855 }
1856
GetPageIdByUrl(const std::string & url)1857 int32_t FrontendDelegateImpl::GetPageIdByUrl(const std::string& url)
1858 {
1859 std::lock_guard<std::mutex> lock(mutex_);
1860 auto pageIter = std::find_if(std::rbegin(pageRouteStack_), std::rend(pageRouteStack_),
1861 [&url](const PageInfo& pageRoute) { return url == pageRoute.url; });
1862 if (pageIter != std::rend(pageRouteStack_)) {
1863 return pageIter->pageId;
1864 }
1865 return INVALID_PAGE_ID;
1866 }
1867
GetPage(int32_t pageId) const1868 RefPtr<JsAcePage> FrontendDelegateImpl::GetPage(int32_t pageId) const
1869 {
1870 std::lock_guard<std::mutex> lock(mutex_);
1871 auto itPage = pageMap_.find(pageId);
1872 if (itPage == pageMap_.end()) {
1873 LOGE("the page is not in the map");
1874 return nullptr;
1875 }
1876 return itPage->second;
1877 }
1878
RegisterFont(const std::string & familyName,const std::string & familySrc,const std::string & bundleName,const std::string & moduleName)1879 void FrontendDelegateImpl::RegisterFont(const std::string& familyName, const std::string& familySrc,
1880 const std::string& bundleName, const std::string& moduleName)
1881 {
1882 pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc, bundleName, moduleName);
1883 }
1884
GetSystemFontList(std::vector<std::string> & fontList)1885 void FrontendDelegateImpl::GetSystemFontList(std::vector<std::string>& fontList)
1886 {
1887 pipelineContextHolder_.Get()->GetSystemFontList(fontList);
1888 }
1889
GetSystemFont(const std::string & fontName,FontInfo & fontInfo)1890 bool FrontendDelegateImpl::GetSystemFont(const std::string& fontName, FontInfo& fontInfo)
1891 {
1892 return pipelineContextHolder_.Get()->GetSystemFont(fontName, fontInfo);
1893 }
1894
GetUIFontConfig(FontConfigJsonInfo & fontConfigJsonInfo)1895 void FrontendDelegateImpl::GetUIFontConfig(FontConfigJsonInfo& fontConfigJsonInfo)
1896 {
1897 pipelineContextHolder_.Get()->GetUIFontConfig(fontConfigJsonInfo);
1898 }
1899
HandleImage(const std::string & src,std::function<void (bool,int32_t,int32_t)> && callback)1900 void FrontendDelegateImpl::HandleImage(const std::string& src, std::function<void(bool, int32_t, int32_t)>&& callback)
1901 {
1902 if (src.empty() || !callback) {
1903 return;
1904 }
1905 auto loadCallback = [jsCallback = std::move(callback), taskExecutor = taskExecutor_](
1906 bool success, int32_t width, int32_t height) {
1907 taskExecutor->PostTask(
1908 [callback = std::move(jsCallback), success, width, height] { callback(success, width, height); },
1909 TaskExecutor::TaskType::JS, "ArkUIHandleImageCallback");
1910 };
1911 pipelineContextHolder_.Get()->TryLoadImageInfo(src, std::move(loadCallback));
1912 }
1913
RequestAnimationFrame(const std::string & callbackId)1914 void FrontendDelegateImpl::RequestAnimationFrame(const std::string& callbackId)
1915 {
1916 CancelableCallback<void()> cancelableTask;
1917 cancelableTask.Reset([callbackId, call = requestAnimationCallback_, weak = AceType::WeakClaim(this)] {
1918 auto delegate = weak.Upgrade();
1919 if (delegate && call) {
1920 call(callbackId, delegate->GetSystemRealTime());
1921 }
1922 });
1923 animationFrameTaskMap_.try_emplace(callbackId, cancelableTask);
1924 animationFrameTaskIds_.emplace(callbackId);
1925 }
1926
GetSystemRealTime()1927 uint64_t FrontendDelegateImpl::GetSystemRealTime()
1928 {
1929 struct timespec ts;
1930 clock_gettime(CLOCK_REALTIME, &ts);
1931 return ts.tv_sec * TO_MILLI + ts.tv_nsec / NANO_TO_MILLI;
1932 }
1933
CancelAnimationFrame(const std::string & callbackId)1934 void FrontendDelegateImpl::CancelAnimationFrame(const std::string& callbackId)
1935 {
1936 auto animationTaskIter = animationFrameTaskMap_.find(callbackId);
1937 if (animationTaskIter != animationFrameTaskMap_.end()) {
1938 animationTaskIter->second.Cancel();
1939 animationFrameTaskMap_.erase(animationTaskIter);
1940 } else {
1941 LOGW("cancelAnimationFrame callbackId not found");
1942 }
1943 }
1944
FlushAnimationTasks()1945 void FrontendDelegateImpl::FlushAnimationTasks()
1946 {
1947 while (!animationFrameTaskIds_.empty()) {
1948 const auto& callbackId = animationFrameTaskIds_.front();
1949 if (!callbackId.empty()) {
1950 auto taskIter = animationFrameTaskMap_.find(callbackId);
1951 if (taskIter != animationFrameTaskMap_.end()) {
1952 taskExecutor_->PostTask(taskIter->second, TaskExecutor::TaskType::JS, "ArkUIFlushAnimationTask");
1953 }
1954 }
1955 animationFrameTaskIds_.pop();
1956 }
1957
1958 auto pageId = GetRunningPageId();
1959 auto page = GetPage(pageId);
1960 if (!page) {
1961 return;
1962 }
1963 auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
1964 if (jsPage && jsPage->GetCommandSize() > 0) {
1965 TriggerPageUpdate(pageId);
1966 }
1967 }
1968
GetAnimationJsTask()1969 SingleTaskExecutor FrontendDelegateImpl::GetAnimationJsTask()
1970 {
1971 return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::JS);
1972 }
1973
GetUiTask()1974 SingleTaskExecutor FrontendDelegateImpl::GetUiTask()
1975 {
1976 return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::UI);
1977 }
1978
AttachPipelineContext(const RefPtr<PipelineBase> & context)1979 void FrontendDelegateImpl::AttachPipelineContext(const RefPtr<PipelineBase>& context)
1980 {
1981 context->SetOnPageShow([weak = AceType::WeakClaim(this)] {
1982 auto delegate = weak.Upgrade();
1983 if (delegate) {
1984 delegate->OnPageShow();
1985 }
1986 });
1987 context->SetAnimationCallback([weak = AceType::WeakClaim(this)] {
1988 auto delegate = weak.Upgrade();
1989 if (delegate) {
1990 delegate->FlushAnimationTasks();
1991 }
1992 });
1993 pipelineContextHolder_.Attach(context);
1994 jsAccessibilityManager_->SetPipelineContext(context);
1995 jsAccessibilityManager_->InitializeCallback();
1996 }
1997
GetPipelineContext()1998 RefPtr<PipelineBase> FrontendDelegateImpl::GetPipelineContext()
1999 {
2000 return pipelineContextHolder_.Get();
2001 }
2002
SetColorMode(ColorMode colorMode)2003 void FrontendDelegateImpl::SetColorMode(ColorMode colorMode)
2004 {
2005 mediaQueryInfo_->EnsureListenerIdValid();
2006 OnMediaQueryUpdate();
2007 }
2008
LoadResourceConfiguration(std::map<std::string,std::string> & mediaResourceFileMap,std::unique_ptr<JsonValue> & currentResourceData)2009 void FrontendDelegateImpl::LoadResourceConfiguration(std::map<std::string, std::string>& mediaResourceFileMap,
2010 std::unique_ptr<JsonValue>& currentResourceData)
2011 {
2012 std::vector<std::string> files;
2013 if (assetManager_) {
2014 assetManager_->GetAssetList(RESOURCES_FOLDER, files);
2015 }
2016
2017 std::set<std::string> resourceFolderName;
2018 for (const auto& file : files) {
2019 resourceFolderName.insert(file.substr(0, file.find_first_of("/")));
2020 }
2021
2022 std::vector<std::string> sortedResourceFolderPath =
2023 AceResConfig::GetDeclarativeResourceFallback(resourceFolderName);
2024 for (const auto& folderName : sortedResourceFolderPath) {
2025 auto fileFullPath = std::string(RESOURCES_FOLDER) + folderName + std::string(I18N_FILE_SUFFIX);
2026 std::string content;
2027 if (GetAssetContent(fileFullPath, content)) {
2028 auto fileData = ParseFileData(content);
2029 if (fileData == nullptr) {
2030 LOGW("parse %{private}s i18n content failed", fileFullPath.c_str());
2031 } else {
2032 currentResourceData->Put(fileData);
2033 }
2034 }
2035 }
2036
2037 std::set<std::string> mediaFileName;
2038 for (const auto& file : files) {
2039 auto mediaPathName = file.substr(file.find_first_of("/"));
2040 std::regex mediaPattern("^\\/media\\/\\w*(\\.jpg|\\.png|\\.gif|\\.svg|\\.webp|\\.bmp)$");
2041 std::smatch result;
2042 if (std::regex_match(mediaPathName, result, mediaPattern)) {
2043 mediaFileName.insert(mediaPathName.substr(mediaPathName.find_first_of("/")));
2044 }
2045 }
2046
2047 auto currentResTag = AceResConfig::GetCurrentDeviceResTag();
2048 auto currentResolutionTag = currentResTag.substr(currentResTag.find_last_of("-") + 1);
2049 for (auto folderName : sortedResourceFolderPath) {
2050 for (auto fileName : mediaFileName) {
2051 if (mediaResourceFileMap.find(fileName) != mediaResourceFileMap.end()) {
2052 continue;
2053 }
2054 auto fullFileName = folderName + fileName;
2055 if (std::find(files.begin(), files.end(), fullFileName) != files.end()) {
2056 mediaResourceFileMap.emplace(fileName.substr(fileName.find_last_of("/") + 1),
2057 std::string(RESOURCES_FOLDER).append(fullFileName));
2058 }
2059 }
2060 if (mediaResourceFileMap.size() == mediaFileName.size()) {
2061 break;
2062 }
2063 }
2064 }
2065
PushJsCallbackToRenderNode(NodeId id,double ratio,std::function<void (bool,double)> && callback)2066 void FrontendDelegateImpl::PushJsCallbackToRenderNode(NodeId id, double ratio,
2067 std::function<void(bool, double)>&& callback)
2068 {
2069 auto visibleCallback = [jsCallback = std::move(callback), executor = taskExecutor_](bool visible, double ratio) {
2070 executor->PostTask(
2071 [task = std::move(jsCallback), visible, ratio] {
2072 if (task) {
2073 task(visible, ratio);
2074 }
2075 },
2076 TaskExecutor::TaskType::JS, "ArkUIJsVisibleCallback");
2077 };
2078 auto uiPushTask = [id, ratio, visibleCallback,
2079 pipeline = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get())]() {
2080 if (pipeline) {
2081 pipeline->PushVisibleCallback(id, ratio, visibleCallback);
2082 }
2083 };
2084 taskExecutor_->PostTask(uiPushTask, TaskExecutor::TaskType::UI, "ArkUIPushVisibleCallback");
2085 }
2086
CallNativeHandler(const std::string & event,const std::string & params)2087 void FrontendDelegateImpl::CallNativeHandler(const std::string& event, const std::string& params)
2088 {
2089 if (callNativeHandler_ != nullptr) {
2090 callNativeHandler_(event, params);
2091 }
2092 }
2093
2094 } // namespace OHOS::Ace::Framework
2095