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