• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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