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