• 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/declarative_frontend/frontend_delegate_declarative.h"
17 
18 #include "base/i18n/localization.h"
19 #include "base/log/event_report.h"
20 #include "base/resource/ace_res_config.h"
21 #include "bridge/common/utils/engine_helper.h"
22 #include "bridge/declarative_frontend/engine/js_converter.h"
23 #include "core/components/toast/toast_component.h"
24 #include "core/components_ng/base/view_abstract.h"
25 #include "core/components_ng/base/view_stack_model.h"
26 #include "core/components_ng/pattern/stage/page_pattern.h"
27 #include "core/components_ng/pattern/overlay/dialog_manager.h"
28 #include "core/components_ng/render/adapter/component_snapshot.h"
29 #include "frameworks/core/common/ace_engine.h"
30 #include "jsview/js_view_abstract.h"
31 #include "core/components_ng/pattern/app_bar/app_bar_view.h"
32 
33 namespace OHOS::Ace::Framework {
34 namespace {
35 
36 constexpr int32_t INVALID_PAGE_ID = -1;
37 constexpr int32_t MAX_ROUTER_STACK = 32;
38 constexpr int32_t TOAST_TIME_MAX = 10000;    // ms
39 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
40 constexpr int32_t MAX_PAGE_ID_SIZE = sizeof(uint64_t) * 8;
41 constexpr int32_t NANO_TO_MILLI = 1000000; // nanosecond to millisecond
42 constexpr int32_t TO_MILLI = 1000;         // second to millisecond
43 constexpr int32_t CALLBACK_ERRORCODE_SUCCESS = 0;
44 constexpr int32_t CALLBACK_ERRORCODE_CANCEL = 1;
45 constexpr int32_t CALLBACK_ERRORCODE_COMPLETE = 2;
46 constexpr int32_t CALLBACK_DATACODE_ZERO = 0;
47 constexpr int32_t USELESS_CHARACTER_SIZE = 2;
48 
49 const char MANIFEST_JSON[] = "manifest.json";
50 const char PAGES_JSON[] = "main_pages.json";
51 const char FILE_TYPE_JSON[] = ".json";
52 const char I18N_FOLDER[] = "i18n/";
53 const char RESOURCES_FOLDER[] = "resources/";
54 const char STYLES_FOLDER[] = "styles/";
55 const char I18N_FILE_SUFFIX[] = "/properties/string.json";
56 
57 // helper function to run OverlayManager task
58 // ensures that the task runs in subwindow instead of main Window
MainWindowOverlay(std::function<void (RefPtr<NG::OverlayManager>)> && task,const std::string & name,const RefPtr<NG::OverlayManager> & overlay)59 void MainWindowOverlay(std::function<void(RefPtr<NG::OverlayManager>)>&& task, const std::string& name,
60     const RefPtr<NG::OverlayManager>& overlay)
61 {
62     auto currentId = Container::CurrentId();
63     ContainerScope scope(currentId);
64     auto context = NG::PipelineContext::GetCurrentContext();
65     CHECK_NULL_VOID(context);
66     auto overlayManager = context->GetOverlayManager();
67     if (overlay) {
68         overlayManager = overlay;
69     }
70     context->GetTaskExecutor()->PostTask(
71         [task = std::move(task), weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
72             auto overlayManager = weak.Upgrade();
73             task(overlayManager);
74         },
75         TaskExecutor::TaskType::UI, name);
76 }
77 
78 } // namespace
79 
GenerateNextPageId()80 int32_t FrontendDelegateDeclarative::GenerateNextPageId()
81 {
82     for (int32_t idx = 0; idx < MAX_PAGE_ID_SIZE; ++idx) {
83         uint64_t bitMask = (1ULL << idx);
84         if ((bitMask & pageIdPool_.fetch_or(bitMask, std::memory_order_relaxed)) == 0) {
85             return idx;
86         }
87     }
88     return INVALID_PAGE_ID;
89 }
90 
RecyclePageId(int32_t pageId)91 void FrontendDelegateDeclarative::RecyclePageId(int32_t pageId)
92 {
93     if (pageId < 0 || pageId >= MAX_PAGE_ID_SIZE) {
94         return;
95     }
96     uint64_t bitMask = (1ULL << pageId);
97     pageIdPool_.fetch_and(~bitMask, std::memory_order_relaxed);
98 }
99 
FrontendDelegateDeclarative(const RefPtr<TaskExecutor> & taskExecutor,const LoadJsCallback & loadCallback,const JsMessageDispatcherSetterCallback & transferCallback,const EventCallback & asyncEventCallback,const EventCallback & syncEventCallback,const UpdatePageCallback & updatePageCallback,const ResetStagingPageCallback & resetLoadingPageCallback,const DestroyPageCallback & destroyPageCallback,const DestroyApplicationCallback & destroyApplicationCallback,const UpdateApplicationStateCallback & updateApplicationStateCallback,const TimerCallback & timerCallback,const MediaQueryCallback & mediaQueryCallback,const LayoutInspectorCallback & layoutInpsectorCallback,const DrawInspectorCallback & drawInpsectorCallback,const RequestAnimationCallback & requestAnimationCallback,const JsCallback & jsCallback,const OnWindowDisplayModeChangedCallBack & onWindowDisplayModeChangedCallBack,const OnConfigurationUpdatedCallBack & onConfigurationUpdatedCallBack,const OnSaveAbilityStateCallBack & onSaveAbilityStateCallBack,const OnRestoreAbilityStateCallBack & onRestoreAbilityStateCallBack,const OnNewWantCallBack & onNewWantCallBack,const OnMemoryLevelCallBack & onMemoryLevelCallBack,const OnStartContinuationCallBack & onStartContinuationCallBack,const OnCompleteContinuationCallBack & onCompleteContinuationCallBack,const OnRemoteTerminatedCallBack & onRemoteTerminatedCallBack,const OnSaveDataCallBack & onSaveDataCallBack,const OnRestoreDataCallBack & onRestoreDataCallBack,const ExternalEventCallback & externalEventCallback)100 FrontendDelegateDeclarative::FrontendDelegateDeclarative(const RefPtr<TaskExecutor>& taskExecutor,
101     const LoadJsCallback& loadCallback, const JsMessageDispatcherSetterCallback& transferCallback,
102     const EventCallback& asyncEventCallback, const EventCallback& syncEventCallback,
103     const UpdatePageCallback& updatePageCallback, const ResetStagingPageCallback& resetLoadingPageCallback,
104     const DestroyPageCallback& destroyPageCallback, const DestroyApplicationCallback& destroyApplicationCallback,
105     const UpdateApplicationStateCallback& updateApplicationStateCallback, const TimerCallback& timerCallback,
106     const MediaQueryCallback& mediaQueryCallback, const LayoutInspectorCallback& layoutInpsectorCallback,
107     const DrawInspectorCallback& drawInpsectorCallback, const RequestAnimationCallback& requestAnimationCallback,
108     const JsCallback& jsCallback, const OnWindowDisplayModeChangedCallBack& onWindowDisplayModeChangedCallBack,
109     const OnConfigurationUpdatedCallBack& onConfigurationUpdatedCallBack,
110     const OnSaveAbilityStateCallBack& onSaveAbilityStateCallBack,
111     const OnRestoreAbilityStateCallBack& onRestoreAbilityStateCallBack, const OnNewWantCallBack& onNewWantCallBack,
112     const OnMemoryLevelCallBack& onMemoryLevelCallBack, const OnStartContinuationCallBack& onStartContinuationCallBack,
113     const OnCompleteContinuationCallBack& onCompleteContinuationCallBack,
114     const OnRemoteTerminatedCallBack& onRemoteTerminatedCallBack, const OnSaveDataCallBack& onSaveDataCallBack,
115     const OnRestoreDataCallBack& onRestoreDataCallBack, const ExternalEventCallback& externalEventCallback)
116     : loadJs_(loadCallback), externalEvent_(externalEventCallback), dispatcherCallback_(transferCallback),
117       asyncEvent_(asyncEventCallback), syncEvent_(syncEventCallback), updatePage_(updatePageCallback),
118       resetStagingPage_(resetLoadingPageCallback), destroyPage_(destroyPageCallback),
119       destroyApplication_(destroyApplicationCallback), updateApplicationState_(updateApplicationStateCallback),
120       timer_(timerCallback), mediaQueryCallback_(mediaQueryCallback), layoutInspectorCallback_(layoutInpsectorCallback),
121       drawInspectorCallback_(drawInpsectorCallback), requestAnimationCallback_(requestAnimationCallback),
122       jsCallback_(jsCallback), onWindowDisplayModeChanged_(onWindowDisplayModeChangedCallBack),
123       onConfigurationUpdated_(onConfigurationUpdatedCallBack), onSaveAbilityState_(onSaveAbilityStateCallBack),
124       onRestoreAbilityState_(onRestoreAbilityStateCallBack), onNewWant_(onNewWantCallBack),
125       onMemoryLevel_(onMemoryLevelCallBack), onStartContinuationCallBack_(onStartContinuationCallBack),
126       onCompleteContinuationCallBack_(onCompleteContinuationCallBack),
127       onRemoteTerminatedCallBack_(onRemoteTerminatedCallBack), onSaveDataCallBack_(onSaveDataCallBack),
128       onRestoreDataCallBack_(onRestoreDataCallBack), manifestParser_(AceType::MakeRefPtr<ManifestParser>()),
129       jsAccessibilityManager_(AccessibilityNodeManager::Create()),
130       mediaQueryInfo_(AceType::MakeRefPtr<MediaQueryInfo>()), taskExecutor_(taskExecutor)
131 {}
132 
~FrontendDelegateDeclarative()133 FrontendDelegateDeclarative::~FrontendDelegateDeclarative()
134 {
135     CHECK_RUN_ON(JS);
136     LOGI("DelegateDeclarative destroyed");
137 }
138 
GetMinPlatformVersion()139 int32_t FrontendDelegateDeclarative::GetMinPlatformVersion()
140 {
141     return manifestParser_->GetMinPlatformVersion();
142 }
143 
RunPage(const std::string & url,const std::string & params,const std::string & profile,bool isNamedRouter)144 UIContentErrorCode FrontendDelegateDeclarative::RunPage(
145     const std::string& url, const std::string& params, const std::string& profile, bool isNamedRouter)
146 {
147     LOGI("RunPage:%{public}s", url.c_str());
148     std::string jsonContent;
149     if (GetAssetContent(MANIFEST_JSON, jsonContent)) {
150         manifestParser_->Parse(jsonContent);
151         manifestParser_->Printer();
152     } else if (!profile.empty() && GetAssetContent(profile, jsonContent)) {
153         manifestParser_->Parse(jsonContent);
154     } else if (GetAssetContent(PAGES_JSON, jsonContent)) {
155         manifestParser_->Parse(jsonContent);
156     } else {
157         EventReport::SendPageRouterException(PageRouterExcepType::RUN_PAGE_ERR, url);
158         return UIContentErrorCode::PARSE_MANIFEST_FAILED;
159     }
160 
161     taskExecutor_->PostTask(
162         [weak = AceType::WeakClaim(this)]() {
163             auto delegate = weak.Upgrade();
164             if (delegate) {
165                 delegate->manifestParser_->GetAppInfo()->ParseI18nJsonInfo();
166             }
167         },
168         TaskExecutor::TaskType::JS, "ArkUIParseI18nJsonInfo");
169 
170     if (Container::IsCurrentUseNewPipeline()) {
171         CHECK_NULL_RETURN(pageRouterManager_, UIContentErrorCode::NULL_PAGE_ROUTER);
172         pageRouterManager_->SetManifestParser(manifestParser_);
173         taskExecutor_->PostTask(
174             [weakPtr = WeakPtr<NG::PageRouterManager>(pageRouterManager_), url, params, isNamedRouter,
175                 weak = AceType::WeakClaim(this)]() {
176                 auto pageRouterManager = weakPtr.Upgrade();
177                 CHECK_NULL_VOID(pageRouterManager);
178                 auto delegate = weak.Upgrade();
179                 if (delegate) {
180                     NG::AppBarView::BuildAppbar(delegate->GetPipelineContext());
181                 }
182                 if (isNamedRouter) {
183                     pageRouterManager->RunPageByNamedRouter(url, params);
184                 } else {
185                     pageRouterManager->RunPage(url, params);
186                 }
187             },
188             TaskExecutor::TaskType::JS, "ArkUIRunPageUrl");
189         return UIContentErrorCode::NO_ERRORS;
190     }
191     if (!url.empty()) {
192         mainPagePath_ = manifestParser_->GetRouter()->GetPagePath(url);
193     } else {
194         mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
195     }
196     RouterTask routerTask;
197     routerTask.action = RouterAction::PUSH;
198     routerTask.target = PageTarget(mainPagePath_);
199     routerTask.params = params;
200     AddRouterTask(routerTask);
201     return LoadPage(GenerateNextPageId(), PageTarget(mainPagePath_), true, params);
202 }
203 
RunPage(const std::shared_ptr<std::vector<uint8_t>> & content,const std::string & params,const std::string & profile)204 void FrontendDelegateDeclarative::RunPage(
205     const std::shared_ptr<std::vector<uint8_t>>& content, const std::string& params, const std::string& profile)
206 {
207     ACE_SCOPED_TRACE("FrontendDelegateDeclarativeNG::RunPage by buffer size:%zu", content->size());
208     taskExecutor_->PostTask(
209         [delegate = Claim(this), weakPtr = WeakPtr<NG::PageRouterManager>(pageRouterManager_), content, params]() {
210             auto pageRouterManager = weakPtr.Upgrade();
211             CHECK_NULL_VOID(pageRouterManager);
212             pageRouterManager->RunPage(content, params);
213             auto pipeline = delegate->GetPipelineContext();
214         },
215         TaskExecutor::TaskType::JS, "ArkUIRunPageContent");
216 }
217 
ChangeLocale(const std::string & language,const std::string & countryOrRegion)218 void FrontendDelegateDeclarative::ChangeLocale(const std::string& language, const std::string& countryOrRegion)
219 {
220     taskExecutor_->PostTask(
221         [language, countryOrRegion]() { AceApplicationInfo::GetInstance().ChangeLocale(language, countryOrRegion); },
222         TaskExecutor::TaskType::PLATFORM, "ArkUIAppInfoChangeLocale");
223 }
224 
GetI18nData(std::unique_ptr<JsonValue> & json)225 void FrontendDelegateDeclarative::GetI18nData(std::unique_ptr<JsonValue>& json)
226 {
227     auto data = JsonUtil::CreateArray(true);
228     GetConfigurationCommon(I18N_FOLDER, data);
229     auto i18nData = JsonUtil::Create(true);
230     i18nData->Put("resources", data);
231     json->Put("i18n", i18nData);
232 }
233 
GetResourceConfiguration(std::unique_ptr<JsonValue> & json)234 void FrontendDelegateDeclarative::GetResourceConfiguration(std::unique_ptr<JsonValue>& json)
235 {
236     auto data = JsonUtil::CreateArray(true);
237     GetConfigurationCommon(RESOURCES_FOLDER, data);
238     json->Put("resourcesConfiguration", data);
239 }
240 
GetConfigurationCommon(const std::string & filePath,std::unique_ptr<JsonValue> & data)241 void FrontendDelegateDeclarative::GetConfigurationCommon(const std::string& filePath, std::unique_ptr<JsonValue>& data)
242 {
243     std::vector<std::string> files;
244     if (assetManager_) {
245         assetManager_->GetAssetList(filePath, files);
246     }
247 
248     std::vector<std::string> fileNameList;
249     for (const auto& file : files) {
250         if (EndWith(file, FILE_TYPE_JSON) && !StartWith(file, STYLES_FOLDER)) {
251             fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
252         }
253     }
254 
255     std::vector<std::string> priorityFileName;
256     if (filePath.compare(I18N_FOLDER) == 0) {
257         auto localeTag = AceApplicationInfo::GetInstance().GetLocaleTag();
258         priorityFileName = AceResConfig::GetLocaleFallback(localeTag, fileNameList);
259     } else {
260         priorityFileName = AceResConfig::GetResourceFallback(fileNameList);
261     }
262 
263     for (const auto& fileName : priorityFileName) {
264         auto fileFullPath = filePath + fileName + std::string(FILE_TYPE_JSON);
265         std::string content;
266         if (GetAssetContent(fileFullPath, content)) {
267             auto fileData = ParseFileData(content);
268             if (fileData == nullptr) {
269                 LOGW("parse %{private}s.json content failed", filePath.c_str());
270             } else {
271                 data->Put(fileData);
272             }
273         }
274     }
275 }
276 
LoadResourceConfiguration(std::map<std::string,std::string> & mediaResourceFileMap,std::unique_ptr<JsonValue> & currentResourceData)277 void FrontendDelegateDeclarative::LoadResourceConfiguration(
278     std::map<std::string, std::string>& mediaResourceFileMap, std::unique_ptr<JsonValue>& currentResourceData)
279 {
280     std::vector<std::string> files;
281     if (assetManager_) {
282         assetManager_->GetAssetList(RESOURCES_FOLDER, files);
283     }
284 
285     std::set<std::string> resourceFolderName;
286     for (const auto& file : files) {
287         if (file.find_first_of("/") != std::string::npos) {
288             resourceFolderName.insert(file.substr(0, file.find_first_of("/")));
289         }
290     }
291 
292     std::vector<std::string> sortedResourceFolderPath =
293         AceResConfig::GetDeclarativeResourceFallback(resourceFolderName);
294     for (const auto& folderName : sortedResourceFolderPath) {
295         auto fileFullPath = std::string(RESOURCES_FOLDER) + folderName + std::string(I18N_FILE_SUFFIX);
296         std::string content;
297         if (GetAssetContent(fileFullPath, content)) {
298             auto fileData = ParseFileData(content);
299             if (fileData == nullptr) {
300                 LOGW("parse %{private}s i18n content failed", fileFullPath.c_str());
301             } else {
302                 currentResourceData->Put(fileData);
303             }
304         }
305     }
306 
307     std::set<std::string> mediaFileName;
308     for (const auto& file : files) {
309         if (file.find_first_of("/") == std::string::npos) {
310             continue;
311         }
312         auto mediaPathName = file.substr(file.find_first_of("/"));
313         std::regex mediaPattern(R"(^\/media\/\w*(\.jpg|\.png|\.gif|\.svg|\.webp|\.bmp)$)");
314         std::smatch result;
315         if (std::regex_match(mediaPathName, result, mediaPattern)) {
316             mediaFileName.insert(mediaPathName.substr(mediaPathName.find_first_of("/")));
317         }
318     }
319 
320     auto currentResTag = AceResConfig::GetCurrentDeviceResTag();
321     auto currentResolutionTag = currentResTag.substr(currentResTag.find_last_of("-") + 1);
322     for (const auto& folderName : sortedResourceFolderPath) {
323         for (const auto& fileName : mediaFileName) {
324             if (mediaResourceFileMap.find(fileName) != mediaResourceFileMap.end()) {
325                 continue;
326             }
327             auto fullFileName = folderName + fileName;
328             if (std::find(files.begin(), files.end(), fullFileName) != files.end()) {
329                 mediaResourceFileMap.emplace(fileName.substr(fileName.find_last_of("/") + 1),
330                     std::string(RESOURCES_FOLDER).append(fullFileName));
331             }
332         }
333         if (mediaResourceFileMap.size() == mediaFileName.size()) {
334             break;
335         }
336     }
337 }
338 
OnJSCallback(const std::string & callbackId,const std::string & data)339 void FrontendDelegateDeclarative::OnJSCallback(const std::string& callbackId, const std::string& data)
340 {
341     taskExecutor_->PostTask(
342         [weak = AceType::WeakClaim(this), callbackId, args = data] {
343             auto delegate = weak.Upgrade();
344             if (delegate) {
345                 delegate->jsCallback_(callbackId, args);
346             }
347         },
348         TaskExecutor::TaskType::JS, "ArkUIHandleJsCallback");
349 }
350 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher) const351 void FrontendDelegateDeclarative::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) const
352 {
353     taskExecutor_->PostTask([dispatcherCallback = dispatcherCallback_, dispatcher] { dispatcherCallback(dispatcher); },
354         TaskExecutor::TaskType::JS, "ArkUISetJsMessageDispatcher");
355 }
356 
TransferComponentResponseData(int32_t callbackId,int32_t,std::vector<uint8_t> && data)357 void FrontendDelegateDeclarative::TransferComponentResponseData(
358     int32_t callbackId, int32_t /*code*/, std::vector<uint8_t>&& data)
359 {
360     auto pipelineContext = pipelineContextHolder_.Get();
361     WeakPtr<PipelineBase> contextWeak(pipelineContext);
362     taskExecutor_->PostTask(
363         [callbackId, data = std::move(data), contextWeak]() mutable {
364             auto context = contextWeak.Upgrade();
365             if (!context) {
366                 LOGE("context is null");
367             } else if (!context->GetMessageBridge()) {
368                 LOGE("messageBridge is null");
369             } else {
370                 context->GetMessageBridge()->HandleCallback(callbackId, std::move(data));
371             }
372         },
373         TaskExecutor::TaskType::UI, "ArkUITransferComponentResponseData");
374 }
375 
TransferJsResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const376 void FrontendDelegateDeclarative::TransferJsResponseData(
377     int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
378 {
379     if (groupJsBridge_ && groupJsBridge_->ForwardToWorker(callbackId)) {
380         groupJsBridge_->TriggerModuleJsCallback(callbackId, code, std::move(data));
381         return;
382     }
383 
384     taskExecutor_->PostTask(
385         [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
386             if (groupJsBridge) {
387                 groupJsBridge->TriggerModuleJsCallback(callbackId, code, std::move(data));
388             }
389         },
390         TaskExecutor::TaskType::JS, "ArkUITransferJsResponseData");
391 }
392 
393 #if defined(PREVIEW)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const394 void FrontendDelegateDeclarative::TransferJsResponseDataPreview(
395     int32_t callbackId, int32_t code, ResponseData responseData) const
396 {
397     LOGI("FrontendDelegateDeclarative TransferJsResponseDataPreview");
398     taskExecutor_->PostTask(
399         [callbackId, code, responseData, groupJsBridge = groupJsBridge_]() mutable {
400             if (groupJsBridge) {
401                 groupJsBridge->TriggerModuleJsCallbackPreview(callbackId, code, responseData);
402             }
403         },
404         TaskExecutor::TaskType::JS, "ArkUITransferJsResponseDataPreview");
405 }
406 #endif
407 
TransferJsPluginGetError(int32_t callbackId,int32_t errorCode,std::string && errorMessage) const408 void FrontendDelegateDeclarative::TransferJsPluginGetError(
409     int32_t callbackId, int32_t errorCode, std::string&& errorMessage) const
410 {
411     taskExecutor_->PostTask(
412         [callbackId, errorCode, errorMessage = std::move(errorMessage), groupJsBridge = groupJsBridge_]() mutable {
413             if (groupJsBridge) {
414                 groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, errorCode, std::move(errorMessage));
415             }
416         },
417         TaskExecutor::TaskType::JS, "ArkUITransferJsPluginGetError");
418 }
419 
TransferJsEventData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const420 void FrontendDelegateDeclarative::TransferJsEventData(
421     int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
422 {
423     taskExecutor_->PostTask(
424         [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
425             if (groupJsBridge) {
426                 groupJsBridge->TriggerEventJsCallback(callbackId, code, std::move(data));
427             }
428         },
429         TaskExecutor::TaskType::JS, "ArkUITransferJsEventData");
430 }
431 
LoadPluginJsCode(std::string && jsCode) const432 void FrontendDelegateDeclarative::LoadPluginJsCode(std::string&& jsCode) const
433 {
434     taskExecutor_->PostTask(
435         [jsCode = std::move(jsCode), groupJsBridge = groupJsBridge_]() mutable {
436             if (groupJsBridge) {
437                 groupJsBridge->LoadPluginJsCode(std::move(jsCode));
438             }
439         },
440         TaskExecutor::TaskType::JS, "ArkUILoadPluginJsCode");
441 }
442 
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen) const443 void FrontendDelegateDeclarative::LoadPluginJsByteCode(
444     std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen) const
445 {
446     if (groupJsBridge_ == nullptr) {
447         LOGE("groupJsBridge_ is nullptr");
448         return;
449     }
450     taskExecutor_->PostTask(
451         [jsCode = std::move(jsCode), jsCodeLen = std::move(jsCodeLen), groupJsBridge = groupJsBridge_]() mutable {
452             groupJsBridge->LoadPluginJsByteCode(std::move(jsCode), std::move(jsCodeLen));
453         },
454         TaskExecutor::TaskType::JS, "ArkUILoadPluginJsByteCode");
455 }
456 
OnPageBackPress()457 bool FrontendDelegateDeclarative::OnPageBackPress()
458 {
459     if (Container::IsCurrentUseNewPipeline()) {
460         CHECK_NULL_RETURN(pageRouterManager_, false);
461         auto pageNode = pageRouterManager_->GetCurrentPageNode();
462         CHECK_NULL_RETURN(pageNode, false);
463         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
464         CHECK_NULL_RETURN(pagePattern, false);
465         if (pagePattern->OnBackPressed()) {
466             TAG_LOGI(AceLogTag::ACE_ROUTER, "router user onBackPress return true");
467             return true;
468         }
469         return pageRouterManager_->Pop();
470     }
471 
472     auto result = false;
473     taskExecutor_->PostSyncTask(
474         [weak = AceType::WeakClaim(this), &result] {
475             auto delegate = weak.Upgrade();
476             if (!delegate) {
477                 return;
478             }
479             auto pageId = delegate->GetRunningPageId();
480             auto page = delegate->GetPage(pageId);
481             if (page) {
482                 result = page->FireDeclarativeOnBackPressCallback();
483             }
484         },
485         TaskExecutor::TaskType::JS, "ArkUIPageBackPress");
486     return result;
487 }
488 
NotifyAppStorage(const WeakPtr<Framework::JsEngine> & jsEngineWeak,const std::string & key,const std::string & value)489 void FrontendDelegateDeclarative::NotifyAppStorage(
490     const WeakPtr<Framework::JsEngine>& jsEngineWeak, const std::string& key, const std::string& value)
491 {
492     taskExecutor_->PostTask(
493         [jsEngineWeak, key, value] {
494             auto jsEngine = jsEngineWeak.Upgrade();
495             if (!jsEngine) {
496                 return;
497             }
498             jsEngine->NotifyAppStorage(key, value);
499         },
500         TaskExecutor::TaskType::JS, "ArkUINotifyAppStorage");
501 }
502 
OnBackGround()503 void FrontendDelegateDeclarative::OnBackGround()
504 {
505     OnPageHide(true);
506 }
507 
OnForeground()508 void FrontendDelegateDeclarative::OnForeground()
509 {
510     // first page show will be called by push page successfully
511     if (Container::IsCurrentUseNewPipeline() || !isFirstNotifyShow_) {
512         OnPageShow(true);
513     }
514     isFirstNotifyShow_ = false;
515 }
516 
OnConfigurationUpdated(const std::string & data)517 void FrontendDelegateDeclarative::OnConfigurationUpdated(const std::string& data)
518 {
519     taskExecutor_->PostSyncTask(
520         [onConfigurationUpdated = onConfigurationUpdated_, data] { onConfigurationUpdated(data); },
521         TaskExecutor::TaskType::JS, "ArkUIConfigurationUpdated");
522     OnMediaQueryUpdate();
523 }
524 
OnStartContinuation()525 bool FrontendDelegateDeclarative::OnStartContinuation()
526 {
527     bool ret = false;
528     taskExecutor_->PostSyncTask(
529         [weak = AceType::WeakClaim(this), &ret] {
530             auto delegate = weak.Upgrade();
531             if (delegate && delegate->onStartContinuationCallBack_) {
532                 ret = delegate->onStartContinuationCallBack_();
533             }
534         },
535         TaskExecutor::TaskType::JS, "ArkUIStartContinuation");
536     return ret;
537 }
538 
OnCompleteContinuation(int32_t code)539 void FrontendDelegateDeclarative::OnCompleteContinuation(int32_t code)
540 {
541     taskExecutor_->PostSyncTask(
542         [weak = AceType::WeakClaim(this), code] {
543             auto delegate = weak.Upgrade();
544             if (delegate && delegate->onCompleteContinuationCallBack_) {
545                 delegate->onCompleteContinuationCallBack_(code);
546             }
547         },
548         TaskExecutor::TaskType::JS, "ArkUICompleteContinuation");
549 }
550 
OnRemoteTerminated()551 void FrontendDelegateDeclarative::OnRemoteTerminated()
552 {
553     taskExecutor_->PostSyncTask(
554         [weak = AceType::WeakClaim(this)] {
555             auto delegate = weak.Upgrade();
556             if (delegate && delegate->onRemoteTerminatedCallBack_) {
557                 delegate->onRemoteTerminatedCallBack_();
558             }
559         },
560         TaskExecutor::TaskType::JS, "ArkUIRemoteTerminated");
561 }
562 
OnSaveData(std::string & data)563 void FrontendDelegateDeclarative::OnSaveData(std::string& data)
564 {
565     std::string savedData;
566     taskExecutor_->PostSyncTask(
567         [weak = AceType::WeakClaim(this), &savedData] {
568             auto delegate = weak.Upgrade();
569             if (delegate && delegate->onSaveDataCallBack_) {
570                 delegate->onSaveDataCallBack_(savedData);
571             }
572         },
573         TaskExecutor::TaskType::JS, "ArkUISaveData");
574     std::string pageUri = GetRunningPageUrl();
575     data = std::string("{\"url\":\"").append(pageUri).append("\",\"__remoteData\":").append(savedData).append("}");
576 }
577 
OnRestoreData(const std::string & data)578 bool FrontendDelegateDeclarative::OnRestoreData(const std::string& data)
579 {
580     bool ret = false;
581     taskExecutor_->PostSyncTask(
582         [weak = AceType::WeakClaim(this), &data, &ret] {
583             auto delegate = weak.Upgrade();
584             if (delegate && delegate->onRestoreDataCallBack_) {
585                 ret = delegate->onRestoreDataCallBack_(data);
586             }
587         },
588         TaskExecutor::TaskType::JS, "ArkUIRestoreData");
589     return ret;
590 }
591 
OnMemoryLevel(const int32_t level)592 void FrontendDelegateDeclarative::OnMemoryLevel(const int32_t level)
593 {
594     taskExecutor_->PostTask(
595         [onMemoryLevel = onMemoryLevel_, level]() {
596             if (onMemoryLevel) {
597                 onMemoryLevel(level);
598             }
599         },
600         TaskExecutor::TaskType::JS, "ArkUIMemoryLevel");
601 }
602 
GetPluginsUsed(std::string & data)603 void FrontendDelegateDeclarative::GetPluginsUsed(std::string& data)
604 {
605     if (!GetAssetContentImpl(assetManager_, "module_collection.txt", data)) {
606         LOGW("read failed, will load all the system plugin");
607         data = "All";
608     }
609 }
610 
OnNewRequest(const std::string & data)611 void FrontendDelegateDeclarative::OnNewRequest(const std::string& data)
612 {
613     FireSyncEvent("_root", std::string("\"onNewRequest\","), data);
614 }
615 
CallPopPage()616 void FrontendDelegateDeclarative::CallPopPage()
617 {
618     LOGI("CallPopPage begin");
619     Back("", "");
620 }
621 
ResetStagingPage()622 void FrontendDelegateDeclarative::ResetStagingPage()
623 {
624     if (resetStagingPage_) {
625         taskExecutor_->PostTask(
626             [resetStagingPage = resetStagingPage_] { resetStagingPage(); },
627             TaskExecutor::TaskType::JS, "ArkUIResetStagingPage");
628     } else {
629         LOGE("resetStagingPage_ is null");
630     }
631 }
632 
OnApplicationDestroy(const std::string & packageName)633 void FrontendDelegateDeclarative::OnApplicationDestroy(const std::string& packageName)
634 {
635     taskExecutor_->PostSyncTask(
636         [destroyApplication = destroyApplication_, packageName] { destroyApplication(packageName); },
637         TaskExecutor::TaskType::JS, "ArkUIApplicationDestroy");
638 }
639 
UpdateApplicationState(const std::string & packageName,Frontend::State state)640 void FrontendDelegateDeclarative::UpdateApplicationState(const std::string& packageName, Frontend::State state)
641 {
642     taskExecutor_->PostTask([updateApplicationState = updateApplicationState_, packageName,
643                                 state] { updateApplicationState(packageName, state); },
644         TaskExecutor::TaskType::JS, "ArkUIUpdateApplicationState");
645 }
646 
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)647 void FrontendDelegateDeclarative::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
648 {
649     taskExecutor_->PostTask([onWindowDisplayModeChanged = onWindowDisplayModeChanged_, isShownInMultiWindow,
650                                 data] { onWindowDisplayModeChanged(isShownInMultiWindow, data); },
651         TaskExecutor::TaskType::JS, "ArkUIWindowDisplayModeChanged");
652 }
653 
OnSaveAbilityState(std::string & data)654 void FrontendDelegateDeclarative::OnSaveAbilityState(std::string& data)
655 {
656     taskExecutor_->PostSyncTask(
657         [onSaveAbilityState = onSaveAbilityState_, &data] { onSaveAbilityState(data); },
658         TaskExecutor::TaskType::JS, "ArkUISaveAbilityState");
659 }
660 
OnRestoreAbilityState(const std::string & data)661 void FrontendDelegateDeclarative::OnRestoreAbilityState(const std::string& data)
662 {
663     taskExecutor_->PostTask([onRestoreAbilityState = onRestoreAbilityState_, data] { onRestoreAbilityState(data); },
664         TaskExecutor::TaskType::JS, "ArkUIRestoreAbilityState");
665 }
666 
OnNewWant(const std::string & data)667 void FrontendDelegateDeclarative::OnNewWant(const std::string& data)
668 {
669     taskExecutor_->PostTask([onNewWant = onNewWant_, data] { onNewWant(data); },
670         TaskExecutor::TaskType::JS, "ArkUINewWant");
671 }
672 
FireAsyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)673 void FrontendDelegateDeclarative::FireAsyncEvent(
674     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
675 {
676     std::string args = param;
677     args.append(",null").append(",null"); // callback and dom changes
678     if (!jsonArgs.empty()) {
679         args.append(",").append(jsonArgs); // method args
680     }
681     taskExecutor_->PostTask(
682         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
683             auto delegate = weak.Upgrade();
684             if (delegate) {
685                 delegate->asyncEvent_(eventId, args);
686             }
687         },
688         TaskExecutor::TaskType::JS, "ArkUIFireAsyncEvent");
689 }
690 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)691 bool FrontendDelegateDeclarative::FireSyncEvent(
692     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
693 {
694     std::string resultStr;
695     FireSyncEvent(eventId, param, jsonArgs, resultStr);
696     return (resultStr == "true");
697 }
698 
FireExternalEvent(const std::string &,const std::string & componentId,const uint32_t nodeId,const bool isDestroy)699 void FrontendDelegateDeclarative::FireExternalEvent(
700     const std::string& /*eventId*/, const std::string& componentId, const uint32_t nodeId, const bool isDestroy)
701 {
702     taskExecutor_->PostSyncTask(
703         [weak = AceType::WeakClaim(this), componentId, nodeId, isDestroy] {
704             auto delegate = weak.Upgrade();
705             if (delegate) {
706                 delegate->externalEvent_(componentId, nodeId, isDestroy);
707             }
708         },
709         TaskExecutor::TaskType::JS, "ArkUIFireExternalEvent");
710 }
711 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs,std::string & result)712 void FrontendDelegateDeclarative::FireSyncEvent(
713     const std::string& eventId, const std::string& param, const std::string& jsonArgs, std::string& result)
714 {
715     int32_t callbackId = callbackCnt_++;
716     std::string args = param;
717     args.append("{\"_callbackId\":\"").append(std::to_string(callbackId)).append("\"}").append(",null");
718     if (!jsonArgs.empty()) {
719         args.append(",").append(jsonArgs); // method args
720     }
721     taskExecutor_->PostSyncTask(
722         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
723             auto delegate = weak.Upgrade();
724             if (delegate) {
725                 delegate->syncEvent_(eventId, args);
726             }
727         },
728         TaskExecutor::TaskType::JS, "ArkUIFireSyncEvent");
729 
730     result = jsCallBackResult_[callbackId];
731     jsCallBackResult_.erase(callbackId);
732 }
733 
FireAccessibilityEvent(const AccessibilityEvent & accessibilityEvent)734 void FrontendDelegateDeclarative::FireAccessibilityEvent(const AccessibilityEvent& accessibilityEvent)
735 {
736     jsAccessibilityManager_->SendAccessibilityAsyncEvent(accessibilityEvent);
737 }
738 
InitializeAccessibilityCallback()739 void FrontendDelegateDeclarative::InitializeAccessibilityCallback()
740 {
741     jsAccessibilityManager_->InitializeCallback();
742 }
743 
GetCurrentPageUrl()744 std::string FrontendDelegateDeclarative::GetCurrentPageUrl()
745 {
746     if (!Container::IsCurrentUseNewPipeline()) {
747         return "";
748     }
749     CHECK_NULL_RETURN(pageRouterManager_, "");
750     return pageRouterManager_->GetCurrentPageUrl();
751 }
752 
753 // Get the currently running JS page information in NG structure.
GetCurrentPageSourceMap()754 RefPtr<RevSourceMap> FrontendDelegateDeclarative::GetCurrentPageSourceMap()
755 {
756     if (!Container::IsCurrentUseNewPipeline()) {
757         return nullptr;
758     }
759     CHECK_NULL_RETURN(pageRouterManager_, nullptr);
760     return pageRouterManager_->GetCurrentPageSourceMap(assetManager_);
761 }
762 
763 // Get the currently running JS page information in NG structure.
GetFaAppSourceMap()764 RefPtr<RevSourceMap> FrontendDelegateDeclarative::GetFaAppSourceMap()
765 {
766     if (!Container::IsCurrentUseNewPipeline()) {
767         return nullptr;
768     }
769     if (appSourceMap_) {
770         return appSourceMap_;
771     }
772     std::string appMap;
773     if (GetAssetContent("app.js.map", appMap)) {
774         appSourceMap_ = AceType::MakeRefPtr<RevSourceMap>();
775         appSourceMap_->Init(appMap);
776     } else {
777         LOGW("app map load failed!");
778     }
779     return appSourceMap_;
780 }
781 
GetStageSourceMap(std::unordered_map<std::string,RefPtr<Framework::RevSourceMap>> & sourceMaps)782 void FrontendDelegateDeclarative::GetStageSourceMap(
783     std::unordered_map<std::string, RefPtr<Framework::RevSourceMap>>& sourceMaps)
784 {
785     if (!Container::IsCurrentUseNewPipeline()) {
786         return;
787     }
788 
789     std::string maps;
790     if (GetAssetContent(MERGE_SOURCEMAPS_PATH, maps)) {
791         auto SourceMap = AceType::MakeRefPtr<RevSourceMap>();
792         SourceMap->StageModeSourceMapSplit(maps, sourceMaps);
793     } else {
794         LOGW("app map load failed!");
795     }
796 }
797 
798 #if defined(PREVIEW)
SetIsComponentPreview(NG::IsComponentPreviewCallback && callback)799 void FrontendDelegateDeclarative::SetIsComponentPreview(NG::IsComponentPreviewCallback&& callback)
800 {
801     pageRouterManager_->SetIsComponentPreview(std::move(callback));
802 }
803 #endif
804 
805 // Start FrontendDelegate overrides.
Push(const std::string & uri,const std::string & params)806 void FrontendDelegateDeclarative::Push(const std::string& uri, const std::string& params)
807 {
808     if (Container::IsCurrentUseNewPipeline()) {
809         CHECK_NULL_VOID(pageRouterManager_);
810         auto currentId = GetEffectiveContainerId();
811         CHECK_EQUAL_VOID(currentId.has_value(), false);
812         ContainerScope scope(currentId.value());
813         NG::RouterPageInfo routerPageInfo;
814         routerPageInfo.url = uri;
815         routerPageInfo.params = params;
816         routerPageInfo.recoverable = true;
817         pageRouterManager_->Push(routerPageInfo);
818         OnMediaQueryUpdate();
819         return;
820     }
821 
822     Push(PageTarget(uri), params);
823 }
824 
PushWithMode(const std::string & uri,const std::string & params,uint32_t routerMode)825 void FrontendDelegateDeclarative::PushWithMode(const std::string& uri, const std::string& params, uint32_t routerMode)
826 {
827     if (Container::IsCurrentUseNewPipeline()) {
828         CHECK_NULL_VOID(pageRouterManager_);
829         auto currentId = GetEffectiveContainerId();
830         CHECK_EQUAL_VOID(currentId.has_value(), false);
831         ContainerScope scope(currentId.value());
832         NG::RouterPageInfo routerPageInfo;
833         routerPageInfo.url = uri;
834         routerPageInfo.params = params;
835         routerPageInfo.recoverable = true;
836         routerPageInfo.routerMode = static_cast<NG::RouterMode>(routerMode);
837         pageRouterManager_->Push(routerPageInfo);
838         OnMediaQueryUpdate();
839         return;
840     }
841     Push(PageTarget(uri, static_cast<RouterMode>(routerMode)), params);
842 }
843 
PushWithCallback(const std::string & uri,const std::string & params,bool recoverable,const std::function<void (const std::string &,int32_t)> & errorCallback,uint32_t routerMode)844 void FrontendDelegateDeclarative::PushWithCallback(const std::string& uri, const std::string& params,
845     bool recoverable, const std::function<void(const std::string&, int32_t)>& errorCallback, uint32_t routerMode)
846 {
847     if (Container::IsCurrentUseNewPipeline()) {
848         CHECK_NULL_VOID(pageRouterManager_);
849         auto currentId = GetEffectiveContainerId();
850         CHECK_EQUAL_VOID(currentId.has_value(), false);
851         ContainerScope scope(currentId.value());
852         NG::RouterPageInfo routerPageInfo;
853         routerPageInfo.url = uri;
854         routerPageInfo.params = params;
855         routerPageInfo.recoverable = recoverable;
856         routerPageInfo.routerMode = static_cast<NG::RouterMode>(routerMode);
857         routerPageInfo.errorCallback = errorCallback;
858         pageRouterManager_->Push(routerPageInfo);
859         OnMediaQueryUpdate();
860         return;
861     }
862     Push(PageTarget(uri, static_cast<RouterMode>(routerMode)), params, errorCallback);
863 }
864 
PushNamedRoute(const std::string & uri,const std::string & params,bool recoverable,const std::function<void (const std::string &,int32_t)> & errorCallback,uint32_t routerMode)865 void FrontendDelegateDeclarative::PushNamedRoute(const std::string& uri, const std::string& params,
866     bool recoverable, const std::function<void(const std::string&, int32_t)>& errorCallback, uint32_t routerMode)
867 {
868     CHECK_NULL_VOID(pageRouterManager_);
869     auto currentId = GetEffectiveContainerId();
870     CHECK_EQUAL_VOID(currentId.has_value(), false);
871     ContainerScope scope(currentId.value());
872     NG::RouterPageInfo routerPageInfo;
873     routerPageInfo.url = uri;
874     routerPageInfo.params = params;
875     routerPageInfo.recoverable = recoverable;
876     routerPageInfo.routerMode = static_cast<NG::RouterMode>(routerMode);
877     routerPageInfo.errorCallback = errorCallback;
878     pageRouterManager_->PushNamedRoute(routerPageInfo);
879     OnMediaQueryUpdate();
880 }
881 
Replace(const std::string & uri,const std::string & params)882 void FrontendDelegateDeclarative::Replace(const std::string& uri, const std::string& params)
883 {
884     if (Container::IsCurrentUseNewPipeline()) {
885         CHECK_NULL_VOID(pageRouterManager_);
886         auto currentId = GetEffectiveContainerId();
887         CHECK_EQUAL_VOID(currentId.has_value(), false);
888         ContainerScope scope(currentId.value());
889         NG::RouterPageInfo routerPageInfo;
890         routerPageInfo.url = uri;
891         routerPageInfo.params = params;
892         routerPageInfo.recoverable = true;
893         pageRouterManager_->Replace(routerPageInfo);
894         OnMediaQueryUpdate();
895         return;
896     }
897     Replace(PageTarget(uri), params);
898 }
899 
ReplaceWithMode(const std::string & uri,const std::string & params,uint32_t routerMode)900 void FrontendDelegateDeclarative::ReplaceWithMode(
901     const std::string& uri, const std::string& params, uint32_t routerMode)
902 {
903     if (Container::IsCurrentUseNewPipeline()) {
904         CHECK_NULL_VOID(pageRouterManager_);
905         auto currentId = GetEffectiveContainerId();
906         CHECK_EQUAL_VOID(currentId.has_value(), false);
907         ContainerScope scope(currentId.value());
908         NG::RouterPageInfo routerPageInfo;
909         routerPageInfo.url = uri;
910         routerPageInfo.params = params;
911         routerPageInfo.recoverable = true;
912         routerPageInfo.routerMode = static_cast<NG::RouterMode>(routerMode);
913         pageRouterManager_->Replace(routerPageInfo);
914         OnMediaQueryUpdate();
915         return;
916     }
917     Replace(PageTarget(uri, static_cast<RouterMode>(routerMode)), params);
918 }
919 
ReplaceWithCallback(const std::string & uri,const std::string & params,bool recoverable,const std::function<void (const std::string &,int32_t)> & errorCallback,uint32_t routerMode)920 void FrontendDelegateDeclarative::ReplaceWithCallback(const std::string& uri, const std::string& params,
921     bool recoverable, const std::function<void(const std::string&, int32_t)>& errorCallback, uint32_t routerMode)
922 {
923     if (Container::IsCurrentUseNewPipeline()) {
924         CHECK_NULL_VOID(pageRouterManager_);
925         auto currentId = GetEffectiveContainerId();
926         CHECK_EQUAL_VOID(currentId.has_value(), false);
927         ContainerScope scope(currentId.value());
928         NG::RouterPageInfo routerPageInfo;
929         routerPageInfo.url = uri;
930         routerPageInfo.params = params;
931         routerPageInfo.recoverable = recoverable;
932         routerPageInfo.routerMode = static_cast<NG::RouterMode>(routerMode);
933         routerPageInfo.errorCallback = errorCallback;
934         pageRouterManager_->Replace(routerPageInfo);
935         OnMediaQueryUpdate();
936         return;
937     }
938     Replace(PageTarget(uri, static_cast<RouterMode>(routerMode)), params, errorCallback);
939 }
940 
ReplaceNamedRoute(const std::string & uri,const std::string & params,bool recoverable,const std::function<void (const std::string &,int32_t)> & errorCallback,uint32_t routerMode)941 void FrontendDelegateDeclarative::ReplaceNamedRoute(const std::string& uri, const std::string& params,
942     bool recoverable, const std::function<void(const std::string&, int32_t)>& errorCallback, uint32_t routerMode)
943 {
944     CHECK_NULL_VOID(pageRouterManager_);
945     auto currentId = GetEffectiveContainerId();
946     CHECK_EQUAL_VOID(currentId.has_value(), false);
947     ContainerScope scope(currentId.value());
948     NG::RouterPageInfo routerPageInfo;
949     routerPageInfo.url = uri;
950     routerPageInfo.params = params;
951     routerPageInfo.recoverable = recoverable;
952     routerPageInfo.routerMode = static_cast<NG::RouterMode>(routerMode);
953     routerPageInfo.errorCallback = errorCallback;
954     pageRouterManager_->ReplaceNamedRoute(routerPageInfo);
955     OnMediaQueryUpdate();
956 }
957 
Back(const std::string & uri,const std::string & params)958 void FrontendDelegateDeclarative::Back(const std::string& uri, const std::string& params)
959 {
960     if (Container::IsCurrentUseNewPipeline()) {
961         CHECK_NULL_VOID(pageRouterManager_);
962         auto currentId = GetEffectiveContainerId();
963         CHECK_EQUAL_VOID(currentId.has_value(), false);
964         ContainerScope scope(currentId.value());
965         NG::RouterPageInfo routerPageInfo;
966         routerPageInfo.url = uri;
967         routerPageInfo.params = params;
968         pageRouterManager_->BackWithTarget(routerPageInfo);
969         OnMediaQueryUpdate();
970         return;
971     }
972     BackWithTarget(PageTarget(uri), params);
973 }
974 
CheckIndexValid(int32_t index) const975 bool FrontendDelegateDeclarative::CheckIndexValid(int32_t index) const
976 {
977     if (index > static_cast<int32_t>(pageRouteStack_.size()) || index <= 0) {
978         LOGE("The index is less than or equal to zero or exceeds the maximum length of the page stack");
979         return false;
980     }
981     return true;
982 }
983 
BackToIndex(int32_t index,const std::string & params)984 void FrontendDelegateDeclarative::BackToIndex(int32_t index, const std::string& params)
985 {
986     if (Container::IsCurrentUseNewPipeline()) {
987         CHECK_NULL_VOID(pageRouterManager_);
988         auto currentId = GetEffectiveContainerId();
989         CHECK_EQUAL_VOID(currentId.has_value(), false);
990         ContainerScope scope(currentId.value());
991         pageRouterManager_->BackToIndexWithTarget(index, params);
992         OnMediaQueryUpdate();
993         return;
994     }
995     if (!CheckIndexValid(index)) {
996         return;
997     }
998     std::string url;
999     int32_t counter = 1;
1000     for (const auto& iter : pageRouteStack_) {
1001         if (counter == index) {
1002             url = iter.url;
1003             break;
1004         }
1005         counter++;
1006     }
1007     BackWithTarget(PageTarget(url), params);
1008 }
1009 
Clear()1010 void FrontendDelegateDeclarative::Clear()
1011 {
1012     if (Container::IsCurrentUseNewPipeline()) {
1013         CHECK_NULL_VOID(pageRouterManager_);
1014         auto currentId = GetEffectiveContainerId();
1015         CHECK_EQUAL_VOID(currentId.has_value(), false);
1016         ContainerScope scope(currentId.value());
1017         pageRouterManager_->Clear();
1018         return;
1019     }
1020     {
1021         std::lock_guard<std::mutex> lock(routerQueueMutex_);
1022         if (!routerQueue_.empty()) {
1023             RouterTask routerTask;
1024             routerTask.action = RouterAction::CLEAR;
1025             AddRouterTask(routerTask);
1026             return;
1027         }
1028         RouterTask routerTask;
1029         routerTask.action = RouterAction::CLEAR;
1030         AddRouterTask(routerTask);
1031     }
1032     ClearInvisiblePages();
1033 }
1034 
GetStackSize() const1035 int32_t FrontendDelegateDeclarative::GetStackSize() const
1036 {
1037     if (Container::IsCurrentUseNewPipeline()) {
1038         CHECK_NULL_RETURN(pageRouterManager_, 0);
1039         auto currentId = GetEffectiveContainerId();
1040         CHECK_EQUAL_RETURN(currentId.has_value(), false, 0);
1041         ContainerScope scope(currentId.value());
1042         return pageRouterManager_->GetStackSize();
1043     }
1044     std::lock_guard<std::mutex> lock(mutex_);
1045     return static_cast<int32_t>(pageRouteStack_.size());
1046 }
1047 
GetCurrentPageIndex() const1048 int32_t FrontendDelegateDeclarative::GetCurrentPageIndex() const
1049 {
1050     if (Container::IsCurrentUseNewPipeline()) {
1051         CHECK_NULL_RETURN(pageRouterManager_, 0);
1052         auto currentId = GetEffectiveContainerId();
1053         CHECK_EQUAL_RETURN(currentId.has_value(), false, 0);
1054         ContainerScope scope(currentId.value());
1055         return pageRouterManager_->GetCurrentPageIndex();
1056     }
1057     std::lock_guard<std::mutex> lock(mutex_);
1058     return static_cast<int32_t>(pageRouteStack_.size());
1059 }
1060 
GetState(int32_t & index,std::string & name,std::string & path)1061 void FrontendDelegateDeclarative::GetState(int32_t& index, std::string& name, std::string& path)
1062 {
1063     if (Container::IsCurrentUseNewPipeline()) {
1064         CHECK_NULL_VOID(pageRouterManager_);
1065         auto currentId = GetEffectiveContainerId();
1066         CHECK_EQUAL_VOID(currentId.has_value(), false);
1067         ContainerScope scope(currentId.value());
1068         pageRouterManager_->GetState(index, name, path);
1069         return;
1070     }
1071 
1072     std::string url;
1073     {
1074         std::lock_guard<std::mutex> lock(mutex_);
1075         if (pageRouteStack_.empty()) {
1076             return;
1077         }
1078         index = static_cast<int32_t>(pageRouteStack_.size());
1079         url = pageRouteStack_.back().url;
1080     }
1081     auto pos = url.rfind(".js");
1082     if (pos == url.length() - 3) {
1083         url = url.substr(0, pos);
1084     }
1085     pos = url.rfind("/");
1086     if (pos != std::string::npos) {
1087         name = url.substr(pos + 1);
1088         path = url.substr(0, pos + 1);
1089     }
1090 }
1091 
GetRouterStateByIndex(int32_t & index,std::string & name,std::string & path,std::string & params)1092 void FrontendDelegateDeclarative::GetRouterStateByIndex(int32_t& index, std::string& name,
1093     std::string& path, std::string& params)
1094 {
1095     if (Container::IsCurrentUseNewPipeline()) {
1096         CHECK_NULL_VOID(pageRouterManager_);
1097         auto currentId = GetEffectiveContainerId();
1098         CHECK_EQUAL_VOID(currentId.has_value(), false);
1099         ContainerScope scope(currentId.value());
1100         pageRouterManager_->GetStateByIndex(index, name, path, params);
1101         return;
1102     }
1103     if (!CheckIndexValid(index)) {
1104         return;
1105     }
1106     std::string url;
1107     {
1108         std::lock_guard<std::mutex> lock(mutex_);
1109         if (pageRouteStack_.empty()) {
1110             LOGI("pageRouteStack is empty");
1111             return;
1112         }
1113         int32_t counter = 1;
1114         for (const auto& iter : pageRouteStack_) {
1115             if (counter == index) {
1116                 url = iter.url;
1117                 break;
1118             }
1119             counter++;
1120         }
1121     }
1122     auto pos = url.rfind(".js");
1123     // url length - (.js) length
1124     if (pos == url.length() - 3) {
1125         url = url.substr(0, pos);
1126     }
1127     pos = url.rfind("/");
1128     if (pos != std::string::npos) {
1129         name = url.substr(pos + 1);
1130         path = url.substr(0, pos + 1);
1131     }
1132     params = GetParams();
1133 }
1134 
IsUnrestoreByIndex(int32_t index)1135 bool FrontendDelegateDeclarative::IsUnrestoreByIndex(int32_t index)
1136 {
1137     if (!Container::IsCurrentUseNewPipeline()) {
1138         return false;
1139     }
1140     CHECK_NULL_RETURN(pageRouterManager_, false);
1141     auto currentId = GetEffectiveContainerId();
1142     CHECK_EQUAL_RETURN(currentId.has_value(), false, false);
1143     ContainerScope scope(currentId.value());
1144     return pageRouterManager_->IsUnrestoreByIndex(index);
1145 }
1146 
GetRouterStateByUrl(std::string & url,std::vector<StateInfo> & stateArray)1147 void FrontendDelegateDeclarative::GetRouterStateByUrl(std::string& url, std::vector<StateInfo>& stateArray)
1148 {
1149     if (Container::IsCurrentUseNewPipeline()) {
1150         CHECK_NULL_VOID(pageRouterManager_);
1151         auto currentId = GetEffectiveContainerId();
1152         CHECK_EQUAL_VOID(currentId.has_value(), false);
1153         ContainerScope scope(currentId.value());
1154         pageRouterManager_->GetStateByUrl(url, stateArray);
1155         return;
1156     }
1157 
1158     int32_t counter = 1;
1159     std::string tempUrl;
1160     StateInfo stateInfo;
1161     {
1162         std::lock_guard<std::mutex> lock(mutex_);
1163         if (pageRouteStack_.empty()) {
1164             LOGI("pageRouteStack is empty");
1165             return;
1166         }
1167         for (const auto& iter : pageRouteStack_) {
1168             if (iter.url == url) {
1169                 stateInfo.index = counter;
1170                 auto pos = url.rfind(".js");
1171                 // url length - (.js) length
1172                 if (pos == url.length() - 3) {
1173                     tempUrl = url.substr(0, pos);
1174                 }
1175                 pos = tempUrl.rfind("/");
1176                 if (pos != std::string::npos) {
1177                     stateInfo.name = tempUrl.substr(pos + 1);
1178                     stateInfo.path = tempUrl.substr(0, pos + 1);
1179                 }
1180                 stateInfo.params = GetParams();
1181                 stateArray.emplace_back(stateInfo);
1182             }
1183             counter++;
1184         }
1185     }
1186 }
1187 
GetParams()1188 std::string FrontendDelegateDeclarative::GetParams()
1189 {
1190     if (Container::IsCurrentUseNewPipeline()) {
1191         CHECK_NULL_RETURN(pageRouterManager_, "");
1192         auto currentId = GetEffectiveContainerId();
1193         CHECK_EQUAL_RETURN(currentId.has_value(), false, "");
1194         ContainerScope scope(currentId.value());
1195         return pageRouterManager_->GetParams();
1196     }
1197     auto iter = pageParamMap_.find(pageId_);
1198     if (iter != pageParamMap_.end()) {
1199         return iter->second;
1200     }
1201     return "";
1202 }
1203 
GetIndexByUrl(const std::string & url)1204 int32_t FrontendDelegateDeclarative::GetIndexByUrl(const std::string& url)
1205 {
1206     if (Container::IsCurrentUseNewPipeline()) {
1207         CHECK_NULL_RETURN(pageRouterManager_, INVALID_PAGE_ID);
1208         auto currentId = GetEffectiveContainerId();
1209         CHECK_EQUAL_RETURN(currentId.has_value(), false, 0);
1210         ContainerScope scope(currentId.value());
1211         return pageRouterManager_->GetIndexByUrl(url);
1212     }
1213     std::lock_guard<std::mutex> lock(mutex_);
1214     for (size_t i = 0; i < pageRouteStack_.size(); ++i) {
1215         if (pageRouteStack_[i].url == url) {
1216             return i;
1217         }
1218     }
1219     return INVALID_PAGE_ID;
1220 }
1221 
AddRouterTask(const RouterTask & task)1222 void FrontendDelegateDeclarative::AddRouterTask(const RouterTask& task)
1223 {
1224     if (routerQueue_.size() < MAX_ROUTER_STACK) {
1225         routerQueue_.emplace(task);
1226     }
1227 }
1228 
ProcessRouterTask()1229 void FrontendDelegateDeclarative::ProcessRouterTask()
1230 {
1231     std::lock_guard<std::mutex> lock(routerQueueMutex_);
1232     if (!routerQueue_.empty()) {
1233         routerQueue_.pop();
1234     }
1235     if (routerQueue_.empty()) {
1236         return;
1237     }
1238     RouterTask currentTask = routerQueue_.front();
1239     LOGI("ProcessRouterTask current size = %{public}zu, action = %{public}d, url = %{public}s", routerQueue_.size(),
1240         static_cast<uint32_t>(currentTask.action), currentTask.target.url.c_str());
1241     taskExecutor_->PostTask(
1242         [weak = AceType::WeakClaim(this), currentTask] {
1243             auto delegate = weak.Upgrade();
1244             if (!delegate) {
1245                 return;
1246             }
1247             switch (currentTask.action) {
1248                 case RouterAction::PUSH:
1249                     delegate->StartPush(currentTask.target, currentTask.params, currentTask.errorCallback);
1250                     break;
1251                 case RouterAction::REPLACE:
1252                     delegate->StartReplace(currentTask.target, currentTask.params, currentTask.errorCallback);
1253                     break;
1254                 case RouterAction::BACK:
1255                     delegate->BackCheckAlert(currentTask.target, currentTask.params);
1256                     break;
1257                 case RouterAction::CLEAR:
1258                     delegate->ClearInvisiblePages();
1259                     break;
1260                 default:
1261                     break;
1262             }
1263         },
1264         TaskExecutor::TaskType::JS, "ArkUIProcessRouterTask");
1265 }
1266 
IsNavigationStage(const PageTarget & target)1267 bool FrontendDelegateDeclarative::IsNavigationStage(const PageTarget& target)
1268 {
1269     return target.container.Upgrade();
1270 }
1271 
Push(const PageTarget & target,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback)1272 void FrontendDelegateDeclarative::Push(const PageTarget& target, const std::string& params,
1273     const std::function<void(const std::string&, int32_t)>& errorCallback)
1274 {
1275     if (IsNavigationStage(target)) {
1276         StartPush(target, params, errorCallback);
1277         return;
1278     }
1279     {
1280         std::lock_guard<std::mutex> lock(routerQueueMutex_);
1281         if (!routerQueue_.empty()) {
1282             AddRouterTask(RouterTask { RouterAction::PUSH, target, params, errorCallback });
1283             return;
1284         }
1285         AddRouterTask(RouterTask { RouterAction::PUSH, target, params, errorCallback });
1286     }
1287     StartPush(target, params, errorCallback);
1288 }
1289 
StartPush(const PageTarget & target,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback)1290 void FrontendDelegateDeclarative::StartPush(const PageTarget& target, const std::string& params,
1291     const std::function<void(const std::string&, int32_t)>& errorCallback)
1292 {
1293     if (target.url.empty()) {
1294         LOGE("router.Push uri is empty");
1295         ProcessRouterTask();
1296         return;
1297     }
1298     if (isRouteStackFull_) {
1299         LOGE("the router stack has reached its max size, you can't push any more pages.");
1300         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, target.url);
1301         if (errorCallback != nullptr) {
1302             errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
1303         }
1304         ProcessRouterTask();
1305         return;
1306     }
1307 
1308     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
1309     if (!pagePath.empty()) {
1310         LoadPage(GenerateNextPageId(), PageTarget(target, pagePath), false, params);
1311         if (errorCallback != nullptr) {
1312             errorCallback("", ERROR_CODE_NO_ERROR);
1313         }
1314     } else {
1315         LOGW("[Engine Log] this uri not support in route push.");
1316         if (errorCallback != nullptr) {
1317             errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR);
1318         }
1319         ProcessRouterTask();
1320     }
1321 }
1322 
Replace(const PageTarget & target,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback)1323 void FrontendDelegateDeclarative::Replace(const PageTarget& target, const std::string& params,
1324     const std::function<void(const std::string&, int32_t)>& errorCallback)
1325 {
1326     if (IsNavigationStage(target)) {
1327         StartReplace(target, params, errorCallback);
1328         return;
1329     }
1330     {
1331         std::lock_guard<std::mutex> lock(routerQueueMutex_);
1332         if (!routerQueue_.empty()) {
1333             AddRouterTask(RouterTask { RouterAction::REPLACE, target, params, errorCallback });
1334             return;
1335         }
1336         AddRouterTask(RouterTask { RouterAction::REPLACE, target, params, errorCallback });
1337     }
1338     StartReplace(target, params, errorCallback);
1339 }
1340 
StartReplace(const PageTarget & target,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback)1341 void FrontendDelegateDeclarative::StartReplace(const PageTarget& target, const std::string& params,
1342     const std::function<void(const std::string&, int32_t)>& errorCallback)
1343 {
1344     if (target.url.empty()) {
1345         LOGE("router.Replace uri is empty");
1346         ProcessRouterTask();
1347         return;
1348     }
1349 
1350     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
1351     if (!pagePath.empty()) {
1352         LoadReplacePage(GenerateNextPageId(), PageTarget(target, pagePath), params);
1353         if (errorCallback != nullptr) {
1354             errorCallback("", ERROR_CODE_NO_ERROR);
1355         }
1356     } else {
1357         LOGW("[Engine Log] this uri not support in route replace.");
1358         if (errorCallback != nullptr) {
1359             errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR_LITE);
1360         }
1361         ProcessRouterTask();
1362     }
1363 }
1364 
PostponePageTransition()1365 void FrontendDelegateDeclarative::PostponePageTransition()
1366 {
1367     taskExecutor_->PostTask(
1368         [weak = AceType::WeakClaim(this)] {
1369             auto delegate = weak.Upgrade();
1370             if (!delegate) {
1371                 return;
1372             }
1373             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1374             pipelineContext->PostponePageTransition();
1375         },
1376         TaskExecutor::TaskType::UI, "ArkUIPostponePageTransition");
1377 }
1378 
LaunchPageTransition()1379 void FrontendDelegateDeclarative::LaunchPageTransition()
1380 {
1381     taskExecutor_->PostTask(
1382         [weak = AceType::WeakClaim(this)] {
1383             auto delegate = weak.Upgrade();
1384             if (!delegate) {
1385                 return;
1386             }
1387             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1388             pipelineContext->LaunchPageTransition();
1389         },
1390         TaskExecutor::TaskType::UI, "ArkUILaunchPageTransition");
1391 }
1392 
BackCheckAlert(const PageTarget & target,const std::string & params)1393 void FrontendDelegateDeclarative::BackCheckAlert(const PageTarget& target, const std::string& params)
1394 {
1395     {
1396         std::lock_guard<std::mutex> lock(mutex_);
1397         if (pageRouteStack_.empty()) {
1398             LOGI("page route stack is empty");
1399             ProcessRouterTask();
1400             return;
1401         }
1402         auto& currentPage = pageRouteStack_.back();
1403         if (currentPage.alertCallback) {
1404             backUri_ = target;
1405             backParam_ = params;
1406             auto context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1407             taskExecutor_->PostTask(
1408                 [context, dialogProperties = pageRouteStack_.back().dialogProperties,
1409                     isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
1410                     if (context) {
1411                         context->ShowDialog(dialogProperties, isRightToLeft);
1412                     }
1413                 },
1414                 TaskExecutor::TaskType::UI, "ArkUIShowDialogBeforeBack");
1415             return;
1416         }
1417     }
1418     StartBack(target, params);
1419 }
1420 
BackWithTarget(const PageTarget & target,const std::string & params)1421 void FrontendDelegateDeclarative::BackWithTarget(const PageTarget& target, const std::string& params)
1422 {
1423     if (IsNavigationStage(target)) {
1424         BackCheckAlert(target, params);
1425         return;
1426     }
1427     {
1428         std::lock_guard<std::mutex> lock(routerQueueMutex_);
1429         if (!routerQueue_.empty()) {
1430             RouterTask routerTask;
1431             routerTask.action = RouterAction::BACK;
1432             routerTask.target = target;
1433             routerTask.params = params;
1434             AddRouterTask(routerTask);
1435             return;
1436         }
1437         RouterTask routerTask;
1438         routerTask.action = RouterAction::BACK;
1439         routerTask.target = target;
1440         routerTask.params = params;
1441         AddRouterTask(routerTask);
1442     }
1443     BackCheckAlert(target, params);
1444 }
1445 
StartBack(const PageTarget & target,const std::string & params)1446 void FrontendDelegateDeclarative::StartBack(const PageTarget& target, const std::string& params)
1447 {
1448     if (target.url.empty()) {
1449         std::string pagePath;
1450         {
1451             std::lock_guard<std::mutex> lock(mutex_);
1452             size_t pageRouteSize = pageRouteStack_.size();
1453             if (pageRouteSize > 1) {
1454                 pageId_ = pageRouteStack_[pageRouteSize - 2].pageId;
1455                 if (!params.empty()) {
1456                     pageParamMap_[pageId_] = params;
1457                 }
1458                 // determine whether the previous page needs to be loaded
1459                 if (pageRouteStack_[pageRouteSize - 2].isRestore) {
1460                     pagePath = pageRouteStack_[pageRouteSize - 2].url;
1461                 }
1462             }
1463         }
1464         if (!pagePath.empty()) {
1465             LoadPage(pageId_, PageTarget(target, pagePath), false, params, true);
1466             return;
1467         }
1468         LOGI("run in normal back");
1469         PopPage();
1470     } else {
1471         std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url, ".js");
1472         if (!pagePath.empty()) {
1473             bool isRestore = false;
1474             pageId_ = GetPageIdByUrl(pagePath, isRestore);
1475             if (isRestore) {
1476                 LoadPage(pageId_, PageTarget(target, pagePath), false, params, true);
1477                 return;
1478             }
1479             if (!params.empty()) {
1480                 std::lock_guard<std::mutex> lock(mutex_);
1481                 pageParamMap_[pageId_] = params;
1482             }
1483             PopToPage(pagePath);
1484         } else {
1485             LOGW("[Engine Log] this uri not support in route Back.");
1486             ProcessRouterTask();
1487         }
1488     }
1489 }
1490 
GetComponentsCount()1491 size_t FrontendDelegateDeclarative::GetComponentsCount()
1492 {
1493     if (Container::IsCurrentUseNewPipeline()) {
1494         CHECK_NULL_RETURN(pageRouterManager_, 0);
1495         auto pageNode = pageRouterManager_->GetCurrentPageNode();
1496         CHECK_NULL_RETURN(pageNode, 0);
1497         return pageNode->GetAllDepthChildrenCount();
1498     }
1499     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1500     CHECK_NULL_RETURN(pipelineContext, 0);
1501     const auto& pageElement = pipelineContext->GetLastPage();
1502     if (pageElement) {
1503         return pageElement->GetComponentsCount();
1504     }
1505     return 0;
1506 }
1507 
TriggerPageUpdate(int32_t pageId,bool directExecute)1508 void FrontendDelegateDeclarative::TriggerPageUpdate(int32_t pageId, bool directExecute)
1509 {
1510     auto page = GetPage(pageId);
1511     if (!page) {
1512         return;
1513     }
1514 
1515     auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
1516     ACE_DCHECK(jsPage);
1517 
1518     // Pop all JS command and execute them in UI thread.
1519     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1520     jsPage->PopAllCommands(*jsCommands);
1521 
1522     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1523     WeakPtr<Framework::JsAcePage> jsPageWeak(jsPage);
1524     WeakPtr<PipelineContext> contextWeak(pipelineContext);
1525     auto updateTask = [jsPageWeak, contextWeak, jsCommands] {
1526         ACE_SCOPED_TRACE("FlushUpdateCommands");
1527         auto jsPage = jsPageWeak.Upgrade();
1528         auto context = contextWeak.Upgrade();
1529         if (!jsPage || !context) {
1530             LOGE("Page update failed. page or context is null.");
1531             EventReport::SendPageRouterException(PageRouterExcepType::UPDATE_PAGE_ERR);
1532             return;
1533         }
1534         // Flush all JS commands.
1535         for (const auto& command : *jsCommands) {
1536             command->Execute(jsPage);
1537         }
1538         if (jsPage->GetDomDocument()) {
1539             jsPage->GetDomDocument()->HandleComponentPostBinding();
1540         }
1541         auto accessibilityManager = context->GetAccessibilityManager();
1542         if (accessibilityManager) {
1543             accessibilityManager->HandleComponentPostBinding();
1544         }
1545 
1546         jsPage->ClearShowCommand();
1547         std::vector<NodeId> dirtyNodes;
1548         jsPage->PopAllDirtyNodes(dirtyNodes);
1549         for (auto nodeId : dirtyNodes) {
1550             auto patchComponent = jsPage->BuildPagePatch(nodeId);
1551             if (patchComponent) {
1552                 context->ScheduleUpdate(patchComponent);
1553             }
1554         }
1555     };
1556 
1557     taskExecutor_->PostTask(
1558         [updateTask, pipelineContext, directExecute]() {
1559             if (pipelineContext) {
1560                 pipelineContext->AddPageUpdateTask(std::move(updateTask), directExecute);
1561             }
1562         },
1563         TaskExecutor::TaskType::UI, "ArkUIAddPageUpdate");
1564 }
1565 
PostJsTask(std::function<void ()> && task,const std::string & name)1566 void FrontendDelegateDeclarative::PostJsTask(std::function<void()>&& task, const std::string& name)
1567 {
1568     taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS, name);
1569 }
1570 
GetAppID() const1571 const std::string& FrontendDelegateDeclarative::GetAppID() const
1572 {
1573     return manifestParser_->GetAppInfo()->GetAppID();
1574 }
1575 
GetAppName() const1576 const std::string& FrontendDelegateDeclarative::GetAppName() const
1577 {
1578     return manifestParser_->GetAppInfo()->GetAppName();
1579 }
1580 
GetVersionName() const1581 const std::string& FrontendDelegateDeclarative::GetVersionName() const
1582 {
1583     return manifestParser_->GetAppInfo()->GetVersionName();
1584 }
1585 
GetVersionCode() const1586 int32_t FrontendDelegateDeclarative::GetVersionCode() const
1587 {
1588     return manifestParser_->GetAppInfo()->GetVersionCode();
1589 }
1590 
MeasureText(MeasureContext context)1591 double FrontendDelegateDeclarative::MeasureText(MeasureContext context)
1592 {
1593     if (context.isFontSizeUseDefaultUnit && context.fontSize.has_value() &&
1594         !AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1595         context.fontSize = Dimension(context.fontSize->Value(), DimensionUnit::VP);
1596     }
1597     return MeasureUtil::MeasureText(context);
1598 }
1599 
MeasureTextSize(MeasureContext context)1600 Size FrontendDelegateDeclarative::MeasureTextSize(MeasureContext context)
1601 {
1602     if (context.isFontSizeUseDefaultUnit && context.fontSize.has_value() &&
1603         !AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1604         context.fontSize = Dimension(context.fontSize->Value(), DimensionUnit::VP);
1605     }
1606     return MeasureUtil::MeasureTextSize(context);
1607 }
1608 
ShowToast(const NG::ToastInfo & toastInfo,std::function<void (int32_t)> && callback)1609 void FrontendDelegateDeclarative::ShowToast(const NG::ToastInfo& toastInfo, std::function<void(int32_t)>&& callback)
1610 {
1611     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show toast enter");
1612     NG::ToastInfo updatedToastInfo = toastInfo;
1613     updatedToastInfo.duration = std::clamp(toastInfo.duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
1614     updatedToastInfo.isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
1615     if (Container::IsCurrentUseNewPipeline()) {
1616         auto task = [updatedToastInfo, callbackParam = std::move(callback), containerId = Container::CurrentId()](
1617                         const RefPtr<NG::OverlayManager>& overlayManager) {
1618             CHECK_NULL_VOID(overlayManager);
1619             ContainerScope scope(containerId);
1620             overlayManager->ShowToast(
1621                 updatedToastInfo, std::move(const_cast<std::function<void(int32_t)>&&>(callbackParam)));
1622         };
1623         MainWindowOverlay(std::move(task), "ArkUIOverlayShowToast", nullptr);
1624         return;
1625     }
1626     auto pipeline = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1627     taskExecutor_->PostTask(
1628         [updatedToastInfo, context = pipeline] {
1629             ToastComponent::GetInstance().Show(context, updatedToastInfo.message, updatedToastInfo.duration,
1630                 updatedToastInfo.bottom, updatedToastInfo.isRightToLeft);
1631         },
1632         TaskExecutor::TaskType::UI, "ArkUIShowToast");
1633 }
1634 
CloseToast(const int32_t toastId,std::function<void (int32_t)> && callback)1635 void FrontendDelegateDeclarative::CloseToast(const int32_t toastId, std::function<void(int32_t)>&& callback)
1636 {
1637     TAG_LOGD(AceLogTag::ACE_OVERLAY, "close toast enter");
1638     auto currentId = Container::CurrentId();
1639     ContainerScope scope(currentId);
1640 
1641     auto context = NG::PipelineContext::GetCurrentContext();
1642     CHECK_NULL_VOID(context);
1643 
1644     auto overlayManager = context->GetOverlayManager();
1645     CHECK_NULL_VOID(overlayManager);
1646     overlayManager->CloseToast(toastId, std::move(callback));
1647 }
1648 
SetToastStopListenerCallback(std::function<void ()> && stopCallback)1649 void FrontendDelegateDeclarative::SetToastStopListenerCallback(std::function<void()>&& stopCallback)
1650 {
1651     TAG_LOGD(AceLogTag::ACE_OVERLAY, "set toast stop listener enter");
1652     ToastComponent::GetInstance().SetToastStopListenerCallback(std::move(stopCallback));
1653 }
1654 
ShowDialogInner(DialogProperties & dialogProperties,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)1655 void FrontendDelegateDeclarative::ShowDialogInner(DialogProperties& dialogProperties,
1656     std::function<void(int32_t, int32_t)>&& callback, const std::set<std::string>& callbacks)
1657 {
1658     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show dialog inner enter");
1659     auto pipelineContext = pipelineContextHolder_.Get();
1660     if (Container::IsCurrentUseNewPipeline()) {
1661         LOGI("Dialog IsCurrentUseNewPipeline.");
1662         dialogProperties.onSuccess = std::move(callback);
1663         dialogProperties.onCancel = [callback, taskExecutor = taskExecutor_] {
1664             taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
1665                 TaskExecutor::TaskType::JS, "ArkUIOverlayShowDialogCancel");
1666         };
1667         auto task = [dialogProperties](const RefPtr<NG::OverlayManager>& overlayManager) {
1668             LOGI("Begin to show dialog ");
1669             CHECK_NULL_VOID(overlayManager);
1670             auto container = Container::Current();
1671             CHECK_NULL_VOID(container);
1672             if (container->IsSubContainer()) {
1673                 auto currentId = SubwindowManager::GetInstance()->GetParentContainerId(Container::CurrentId());
1674                 container = AceEngine::Get().GetContainer(currentId);
1675                 CHECK_NULL_VOID(container);
1676             }
1677             RefPtr<NG::FrameNode> dialog;
1678             if (dialogProperties.isShowInSubWindow) {
1679                 dialog = SubwindowManager::GetInstance()->ShowDialogNG(dialogProperties, nullptr);
1680                 CHECK_NULL_VOID(dialog);
1681                 if (dialogProperties.isModal && !container->IsUIExtensionWindow()) {
1682                     DialogProperties Maskarg;
1683                     Maskarg.isMask = true;
1684                     Maskarg.autoCancel = dialogProperties.autoCancel;
1685                     auto mask = overlayManager->ShowDialog(Maskarg, nullptr, false);
1686                     CHECK_NULL_VOID(mask);
1687                     overlayManager->SetMaskNodeId(dialog->GetId(), mask->GetId());
1688                 }
1689             } else {
1690                 dialog = overlayManager->ShowDialog(
1691                     dialogProperties, nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1692                 CHECK_NULL_VOID(dialog);
1693             }
1694         };
1695         if (dialogProperties.dialogLevelMode == LevelMode::EMBEDDED) {
1696             NG::DialogManager::ShowInEmbeddedOverlay(
1697                 std::move(task), "ArkUIOverlayShowDialog", dialogProperties.dialogLevelUniqueId);
1698         } else {
1699             MainWindowOverlay(std::move(task), "ArkUIOverlayShowDialog", nullptr);
1700         }
1701         return;
1702     }
1703     std::unordered_map<std::string, EventMarker> callbackMarkers;
1704     if (callbacks.find(COMMON_SUCCESS) != callbacks.end()) {
1705         auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
1706         BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
1707             successEventMarker, [callback, taskExecutor = taskExecutor_](int32_t successType) {
1708                 taskExecutor->PostTask([callback, successType]() { callback(CALLBACK_ERRORCODE_SUCCESS, successType); },
1709                     TaskExecutor::TaskType::JS, "ArkUIShowDialogSuccessCallback");
1710             });
1711         callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1712     }
1713 
1714     if (callbacks.find(COMMON_CANCEL) != callbacks.end()) {
1715         auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1716         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1717             cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
1718                 taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
1719                     TaskExecutor::TaskType::JS, "ArkUIShowDialogCancelCallback");
1720             });
1721         callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
1722     }
1723 
1724     if (callbacks.find(COMMON_COMPLETE) != callbacks.end()) {
1725         auto completeEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1726         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1727             completeEventMarker, [callback, taskExecutor = taskExecutor_] {
1728                 taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_COMPLETE, CALLBACK_DATACODE_ZERO); },
1729                     TaskExecutor::TaskType::JS, "ArkUIShowDialogCompleteCallback");
1730             });
1731         callbackMarkers.emplace(COMMON_COMPLETE, completeEventMarker);
1732     }
1733     dialogProperties.callbacks = std::move(callbackMarkers);
1734     auto context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1735     CHECK_NULL_VOID(context);
1736     context->ShowDialog(dialogProperties, AceApplicationInfo::GetInstance().IsRightToLeft());
1737 }
1738 
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)1739 void FrontendDelegateDeclarative::ShowDialog(const std::string& title, const std::string& message,
1740     const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
1741     const std::set<std::string>& callbacks)
1742 {
1743     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show dialog enter");
1744     DialogProperties dialogProperties = {
1745         .type = DialogType::ALERT_DIALOG,
1746         .title = title,
1747         .content = message,
1748         .autoCancel = autoCancel,
1749         .buttons = buttons,
1750     };
1751     ShowDialogInner(dialogProperties, std::move(callback), callbacks);
1752 }
1753 
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,std::function<void (bool)> && onStatusChanged)1754 void FrontendDelegateDeclarative::ShowDialog(const std::string& title, const std::string& message,
1755     const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
1756     const std::set<std::string>& callbacks, std::function<void(bool)>&& onStatusChanged)
1757 {
1758     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show dialog enter with status changed");
1759     DialogProperties dialogProperties = {
1760         .type = DialogType::ALERT_DIALOG,
1761         .title = title,
1762         .content = message,
1763         .autoCancel = autoCancel,
1764         .buttons = buttons,
1765         .onStatusChanged = std::move(onStatusChanged),
1766     };
1767     ShowDialogInner(dialogProperties, std::move(callback), callbacks);
1768 }
1769 
ShowDialog(const PromptDialogAttr & dialogAttr,const std::vector<ButtonInfo> & buttons,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)1770 void FrontendDelegateDeclarative::ShowDialog(const PromptDialogAttr& dialogAttr, const std::vector<ButtonInfo>& buttons,
1771     std::function<void(int32_t, int32_t)>&& callback, const std::set<std::string>& callbacks)
1772 {
1773     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show dialog enter with attr");
1774     DialogProperties dialogProperties = {
1775         .type = DialogType::ALERT_DIALOG,
1776         .title = dialogAttr.title,
1777         .content = dialogAttr.message,
1778         .autoCancel = dialogAttr.autoCancel,
1779         .buttons = buttons,
1780         .onLanguageChange = dialogAttr.onLanguageChange,
1781         .isShowInSubWindow = dialogAttr.showInSubWindow,
1782         .isModal = dialogAttr.isModal,
1783         .enableHoverMode = dialogAttr.enableHoverMode,
1784         .maskRect = dialogAttr.maskRect,
1785         .levelOrder = dialogAttr.levelOrder,
1786         .dialogLevelMode = dialogAttr.dialogLevelMode,
1787         .dialogLevelUniqueId = dialogAttr.dialogLevelUniqueId,
1788         .dialogImmersiveMode = dialogAttr.dialogImmersiveMode,
1789         .blurStyleOption = dialogAttr.blurStyleOption,
1790         .effectOption = dialogAttr.effectOption
1791     };
1792 #if defined(PREVIEW)
1793     if (dialogProperties.isShowInSubWindow) {
1794         LOGW("[Engine Log] Unable to use the SubWindow in the Previewer. Perform this operation on the "
1795              "emulator or a real device instead.");
1796         dialogProperties.isShowInSubWindow = false;
1797     }
1798 #endif
1799     if (dialogAttr.alignment.has_value()) {
1800         dialogProperties.alignment = dialogAttr.alignment.value();
1801     }
1802     if (dialogAttr.offset.has_value()) {
1803         dialogProperties.offset = dialogAttr.offset.value();
1804     }
1805     if (dialogAttr.shadow.has_value()) {
1806         dialogProperties.shadow = dialogAttr.shadow.value();
1807     }
1808     if (dialogAttr.backgroundColor.has_value()) {
1809         dialogProperties.backgroundColor = dialogAttr.backgroundColor.value();
1810     }
1811     if (dialogAttr.backgroundBlurStyle.has_value()) {
1812         dialogProperties.backgroundBlurStyle = dialogAttr.backgroundBlurStyle.value();
1813     }
1814     if (dialogAttr.hoverModeArea.has_value()) {
1815         dialogProperties.hoverModeArea = dialogAttr.hoverModeArea.value();
1816     }
1817     ShowDialogInner(dialogProperties, std::move(callback), callbacks);
1818 }
1819 
ShowDialog(const PromptDialogAttr & dialogAttr,const std::vector<ButtonInfo> & buttons,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks,std::function<void (bool)> && onStatusChanged)1820 void FrontendDelegateDeclarative::ShowDialog(const PromptDialogAttr& dialogAttr, const std::vector<ButtonInfo>& buttons,
1821     std::function<void(int32_t, int32_t)>&& callback, const std::set<std::string>& callbacks,
1822     std::function<void(bool)>&& onStatusChanged)
1823 {
1824     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show dialog enter with attr for status changed");
1825     DialogProperties dialogProperties = {
1826         .type = DialogType::ALERT_DIALOG,
1827         .title = dialogAttr.title,
1828         .content = dialogAttr.message,
1829         .autoCancel = dialogAttr.autoCancel,
1830         .buttons = buttons,
1831         .isShowInSubWindow = dialogAttr.showInSubWindow,
1832         .isModal = dialogAttr.isModal,
1833         .onStatusChanged = std::move(onStatusChanged),
1834         .maskRect = dialogAttr.maskRect,
1835         .levelOrder = dialogAttr.levelOrder,
1836     };
1837 #if defined(PREVIEW)
1838     if (dialogProperties.isShowInSubWindow) {
1839         LOGW("[Engine Log] Unable to use the SubWindow in the Previewer. Perform this operation on the "
1840              "emulator or a real device instead.");
1841         dialogProperties.isShowInSubWindow = false;
1842     }
1843 #endif
1844     if (dialogAttr.alignment.has_value()) {
1845         dialogProperties.alignment = dialogAttr.alignment.value();
1846     }
1847     if (dialogAttr.offset.has_value()) {
1848         dialogProperties.offset = dialogAttr.offset.value();
1849     }
1850     ShowDialogInner(dialogProperties, std::move(callback), callbacks);
1851 }
1852 
RemoveCustomDialog(int32_t instanceId)1853 void FrontendDelegateDeclarative::RemoveCustomDialog(int32_t instanceId)
1854 {
1855     TAG_LOGI(AceLogTag::ACE_DIALOG, "Dismiss custom dialog, instanceId: %{public}d", instanceId);
1856     ContainerScope scope(instanceId);
1857     NG::ViewAbstract::DismissDialog();
1858 }
1859 
ParsePropertiesFromAttr(const PromptDialogAttr & dialogAttr)1860 DialogProperties FrontendDelegateDeclarative::ParsePropertiesFromAttr(const PromptDialogAttr &dialogAttr)
1861 {
1862     DialogProperties dialogProperties = {
1863         .autoCancel = dialogAttr.autoCancel, .customStyle = dialogAttr.customStyle,
1864         .onWillDismiss = dialogAttr.customOnWillDismiss, .maskColor = dialogAttr.maskColor,
1865         .backgroundColor = dialogAttr.backgroundColor, .borderRadius = dialogAttr.borderRadius,
1866         .isShowInSubWindow = dialogAttr.showInSubWindow, .isModal = dialogAttr.isModal,
1867         .enableHoverMode = dialogAttr.enableHoverMode, .customBuilder = dialogAttr.customBuilder,
1868         .customBuilderWithId = dialogAttr.customBuilderWithId,
1869         .blurStyleOption = dialogAttr.blurStyleOption,
1870         .effectOption = dialogAttr.effectOption,
1871         .borderWidth = dialogAttr.borderWidth,
1872         .borderColor = dialogAttr.borderColor, .borderStyle = dialogAttr.borderStyle, .shadow = dialogAttr.shadow,
1873         .width = dialogAttr.width, .height = dialogAttr.height,
1874         .isUserCreatedDialog = dialogAttr.isUserCreatedDialog,
1875         .maskRect = dialogAttr.maskRect,
1876         .transitionEffect = dialogAttr.transitionEffect, .dialogTransitionEffect = dialogAttr.dialogTransitionEffect,
1877         .maskTransitionEffect = dialogAttr.maskTransitionEffect, .contentNode = dialogAttr.contentNode,
1878         .onDidAppear = dialogAttr.onDidAppear, .onDidDisappear = dialogAttr.onDidDisappear,
1879         .onWillAppear = dialogAttr.onWillAppear, .onWillDisappear = dialogAttr.onWillDisappear,
1880         .keyboardAvoidMode = dialogAttr.keyboardAvoidMode, .dialogCallback = dialogAttr.dialogCallback,
1881         .keyboardAvoidDistance = dialogAttr.keyboardAvoidDistance,
1882         .levelOrder = dialogAttr.levelOrder,
1883         .focusable = dialogAttr.focusable,
1884         .dialogLevelMode = dialogAttr.dialogLevelMode,
1885         .dialogLevelUniqueId = dialogAttr.dialogLevelUniqueId,
1886         .dialogImmersiveMode = dialogAttr.dialogImmersiveMode
1887     };
1888 #if defined(PREVIEW)
1889     if (dialogProperties.isShowInSubWindow) {
1890         LOGW("[Engine Log] Unable to use the SubWindow in the Previewer. Perform this operation on the "
1891              "emulator or a real device instead.");
1892         dialogProperties.isShowInSubWindow = false;
1893     }
1894 #endif
1895     if (dialogAttr.alignment.has_value()) {
1896         dialogProperties.alignment = dialogAttr.alignment.value();
1897     }
1898     if (dialogAttr.offset.has_value()) {
1899         dialogProperties.offset = dialogAttr.offset.value();
1900     }
1901     if (dialogAttr.hoverModeArea.has_value()) {
1902         dialogProperties.hoverModeArea = dialogAttr.hoverModeArea.value();
1903     }
1904     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1905         dialogProperties.isSysBlurStyle = false;
1906     } else {
1907         if (dialogAttr.backgroundBlurStyle.has_value()) {
1908             dialogProperties.backgroundBlurStyle = dialogAttr.backgroundBlurStyle.value();
1909         }
1910     }
1911     return dialogProperties;
1912 }
1913 
OpenCustomDialog(const PromptDialogAttr & dialogAttr,std::function<void (int32_t)> && callback)1914 void FrontendDelegateDeclarative::OpenCustomDialog(const PromptDialogAttr &dialogAttr,
1915     std::function<void(int32_t)> &&callback)
1916 {
1917     DialogProperties dialogProperties = ParsePropertiesFromAttr(dialogAttr);
1918     if (Container::IsCurrentUseNewPipeline()) {
1919         TAG_LOGI(AceLogTag::ACE_OVERLAY, "Dialog IsCurrentUseNewPipeline.");
1920         auto task = [dialogAttr, dialogProperties, callback](const RefPtr<NG::OverlayManager>& overlayManager) mutable {
1921             CHECK_NULL_VOID(overlayManager);
1922             TAG_LOGI(AceLogTag::ACE_OVERLAY, "open custom dialog isShowInSubWindow %{public}d",
1923                 dialogProperties.isShowInSubWindow);
1924             if (dialogProperties.isShowInSubWindow) {
1925                 SubwindowManager::GetInstance()->OpenCustomDialogNG(dialogProperties, std::move(callback));
1926                 if (dialogProperties.isModal) {
1927                     TAG_LOGW(AceLogTag::ACE_OVERLAY, "temporary not support isShowInSubWindow and isModal");
1928                 }
1929             } else {
1930                 overlayManager->OpenCustomDialog(dialogProperties, std::move(callback));
1931             }
1932         };
1933         if (dialogProperties.dialogLevelMode == LevelMode::EMBEDDED) {
1934             NG::DialogManager::ShowInEmbeddedOverlay(
1935                 std::move(task), "ArkUIOverlayShowDialog", dialogProperties.dialogLevelUniqueId);
1936         } else {
1937             MainWindowOverlay(std::move(task), "ArkUIOverlayShowDialog", nullptr);
1938         }
1939         return;
1940     } else {
1941         LOGW("not support old pipeline");
1942     }
1943 }
1944 
CloseCustomDialog(const int32_t dialogId)1945 void FrontendDelegateDeclarative::CloseCustomDialog(const int32_t dialogId)
1946 {
1947     auto task = [dialogId](const RefPtr<NG::OverlayManager>& overlayManager) {
1948         CHECK_NULL_VOID(overlayManager);
1949         TAG_LOGI(AceLogTag::ACE_OVERLAY, "begin to close custom dialog.");
1950         overlayManager->CloseCustomDialog(dialogId);
1951         SubwindowManager::GetInstance()->CloseCustomDialogNG(dialogId);
1952     };
1953     auto dialogNode = NG::FrameNode::GetFrameNodeOnly(V2::DIALOG_ETS_TAG, dialogId);
1954     auto currentOverlay = NG::DialogManager::GetInstance().GetEmbeddedOverlayWithNode(dialogNode);
1955     MainWindowOverlay(std::move(task), "ArkUIOverlayCloseCustomDialog", currentOverlay);
1956     return;
1957 }
1958 
CloseCustomDialog(const WeakPtr<NG::UINode> & node,std::function<void (int32_t)> && callback)1959 void FrontendDelegateDeclarative::CloseCustomDialog(const WeakPtr<NG::UINode>& node,
1960     std::function<void(int32_t)> &&callback)
1961 {
1962     auto nodePtr = node.Upgrade();
1963     CHECK_NULL_VOID(nodePtr);
1964     auto context = nodePtr->GetContextWithCheck();
1965     CHECK_NULL_VOID(context);
1966     auto overlayManager = context->GetOverlayManager();
1967     auto parent = NG::DialogManager::GetInstance().GetDialogNodeByContentNode(nodePtr);
1968     if (parent) {
1969         auto currentOverlay = NG::DialogManager::GetInstance().GetEmbeddedOverlayWithNode(parent);
1970         if (currentOverlay) {
1971             overlayManager = currentOverlay;
1972         }
1973     }
1974     context->GetTaskExecutor()->PostTask(
1975         [node, callback, weak = WeakPtr<NG::OverlayManager>(overlayManager)]() mutable {
1976             auto overlayManager = weak.Upgrade();
1977             CHECK_NULL_VOID(overlayManager);
1978             TAG_LOGI(AceLogTag::ACE_OVERLAY, "begin to close custom dialog.");
1979             overlayManager->CloseCustomDialog(node, std::move(callback));
1980         },
1981         TaskExecutor::TaskType::UI, "ArkUIOverlayCloseCustomDialog");
1982 }
1983 
UpdateCustomDialog(const WeakPtr<NG::UINode> & node,const PromptDialogAttr & dialogAttr,std::function<void (int32_t)> && callback)1984 void FrontendDelegateDeclarative::UpdateCustomDialog(
1985     const WeakPtr<NG::UINode>& node, const PromptDialogAttr &dialogAttr, std::function<void(int32_t)> &&callback)
1986 {
1987     DialogProperties dialogProperties = {
1988         .autoCancel = dialogAttr.autoCancel,
1989         .maskColor = dialogAttr.maskColor,
1990         .isSysBlurStyle = false
1991     };
1992     if (dialogAttr.alignment.has_value()) {
1993         dialogProperties.alignment = dialogAttr.alignment.value();
1994     }
1995     if (dialogAttr.offset.has_value()) {
1996         dialogProperties.offset = dialogAttr.offset.value();
1997     }
1998 
1999     auto nodePtr = node.Upgrade();
2000     CHECK_NULL_VOID(nodePtr);
2001     auto context = nodePtr->GetContextWithCheck();
2002     CHECK_NULL_VOID(context);
2003     auto overlayManager = context->GetOverlayManager();
2004     context->GetTaskExecutor()->PostTask(
2005         [dialogProperties, node, callback, weak = WeakPtr<NG::OverlayManager>(overlayManager)]() mutable {
2006             auto overlayManager = weak.Upgrade();
2007             CHECK_NULL_VOID(overlayManager);
2008             TAG_LOGI(AceLogTag::ACE_OVERLAY, "begin to update custom dialog.");
2009             overlayManager->UpdateCustomDialog(node, dialogProperties, std::move(callback));
2010         },
2011         TaskExecutor::TaskType::UI, "ArkUIOverlayUpdateCustomDialog");
2012 }
2013 
GetTopOrder()2014 std::optional<double> FrontendDelegateDeclarative::GetTopOrder()
2015 {
2016     auto currentId = Container::CurrentId();
2017     ContainerScope scope(currentId);
2018     auto context = NG::PipelineContext::GetCurrentContext();
2019     CHECK_NULL_RETURN(context, std::nullopt);
2020     auto overlayManager = context->GetOverlayManager();
2021     CHECK_NULL_RETURN(overlayManager, std::nullopt);
2022     return overlayManager->GetTopOrder();
2023 }
2024 
GetBottomOrder()2025 std::optional<double> FrontendDelegateDeclarative::GetBottomOrder()
2026 {
2027     auto currentId = Container::CurrentId();
2028     ContainerScope scope(currentId);
2029     auto context = NG::PipelineContext::GetCurrentContext();
2030     CHECK_NULL_RETURN(context, std::nullopt);
2031     auto overlayManager = context->GetOverlayManager();
2032     CHECK_NULL_RETURN(overlayManager, std::nullopt);
2033     return overlayManager->GetBottomOrder();
2034 }
2035 
ShowActionMenuInner(DialogProperties & dialogProperties,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)2036 void FrontendDelegateDeclarative::ShowActionMenuInner(DialogProperties& dialogProperties,
2037     const std::vector<ButtonInfo>& button, std::function<void(int32_t, int32_t)>&& callback)
2038 {
2039     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show action menu inner enter");
2040     if (Container::IsCurrentUseNewPipeline()) {
2041         ShowActionMenuInnerNG(dialogProperties, button, std::move(callback));
2042         return;
2043     }
2044 
2045     std::unordered_map<std::string, EventMarker> callbackMarkers;
2046     auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
2047     BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
2048         successEventMarker, [callback, number = button.size(), taskExecutor = taskExecutor_](int32_t successType) {
2049             taskExecutor->PostTask(
2050                 [callback, number, successType]() {
2051                     // if callback index is larger than button's number, cancel button is selected
2052                     if (static_cast<size_t>(successType) == number) {
2053                         callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO);
2054                     } else {
2055                         callback(CALLBACK_ERRORCODE_SUCCESS, successType);
2056                     }
2057                 },
2058                 TaskExecutor::TaskType::JS, "ArkUIDialogShowActionMenuSuccess");
2059         });
2060     callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
2061 
2062     auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
2063     BackEndEventManager<void()>::GetInstance().BindBackendEvent(
2064         cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
2065             taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
2066                 TaskExecutor::TaskType::JS, "ArkUIDialogShowActionMenuCancel");
2067         });
2068     callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
2069     dialogProperties.callbacks = std::move(callbackMarkers);
2070     auto context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
2071     CHECK_NULL_VOID(context);
2072     context->ShowDialog(dialogProperties, AceApplicationInfo::GetInstance().IsRightToLeft());
2073 }
2074 
ShowActionMenuInnerNG(DialogProperties & dialogProperties,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)2075 void FrontendDelegateDeclarative::ShowActionMenuInnerNG(DialogProperties& dialogProperties,
2076     const std::vector<ButtonInfo>& button, std::function<void(int32_t, int32_t)>&& callback)
2077 {
2078     TAG_LOGI(AceLogTag::ACE_OVERLAY, "show action menu with new pipeline");
2079     dialogProperties.onSuccess = std::move(callback);
2080     dialogProperties.onCancel = [callback, taskExecutor = taskExecutor_] {
2081         taskExecutor->PostTask(
2082             [callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
2083             TaskExecutor::TaskType::JS, "ArkUIOverlayShowActionMenuCancel");
2084     };
2085     auto context = DynamicCast<NG::PipelineContext>(pipelineContextHolder_.Get());
2086     auto overlayManager = context ? context->GetOverlayManager() : nullptr;
2087     if (dialogProperties.dialogLevelMode == LevelMode::EMBEDDED) {
2088         auto embeddedOverlay = NG::DialogManager::GetEmbeddedOverlay(dialogProperties.dialogLevelUniqueId, context);
2089         if (embeddedOverlay) {
2090             overlayManager = embeddedOverlay;
2091         }
2092     }
2093     taskExecutor_->PostTask(
2094         [dialogProperties, weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
2095             auto overlayManager = weak.Upgrade();
2096             CHECK_NULL_VOID(overlayManager);
2097             auto container = Container::Current();
2098             CHECK_NULL_VOID(container);
2099             if (container->IsSubContainer()) {
2100                 auto currentId = SubwindowManager::GetInstance()->GetParentContainerId(Container::CurrentId());
2101                 container = AceEngine::Get().GetContainer(currentId);
2102                 CHECK_NULL_VOID(container);
2103             }
2104             RefPtr<NG::FrameNode> dialog;
2105             if (dialogProperties.isShowInSubWindow) {
2106                 dialog = SubwindowManager::GetInstance()->ShowDialogNG(dialogProperties, nullptr);
2107                 CHECK_NULL_VOID(dialog);
2108                 if (dialogProperties.isModal && !container->IsUIExtensionWindow()) {
2109                     DialogProperties Maskarg;
2110                     Maskarg.isMask = true;
2111                     Maskarg.autoCancel = dialogProperties.autoCancel;
2112                     auto mask = overlayManager->ShowDialog(Maskarg, nullptr, false);
2113                     CHECK_NULL_VOID(mask);
2114                     overlayManager->SetMaskNodeId(dialog->GetId(), mask->GetId());
2115                 }
2116             } else {
2117                 dialog = overlayManager->ShowDialog(
2118                     dialogProperties, nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
2119                 CHECK_NULL_VOID(dialog);
2120             }
2121         },
2122         TaskExecutor::TaskType::UI, "ArkUIOverlayShowActionMenuInner");
2123 }
2124 
ShowActionMenu(const std::string & title,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)2125 void FrontendDelegateDeclarative::ShowActionMenu(
2126     const std::string& title, const std::vector<ButtonInfo>& button, std::function<void(int32_t, int32_t)>&& callback)
2127 {
2128     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show action menu enter");
2129     DialogProperties dialogProperties = {
2130         .title = title,
2131         .autoCancel = true,
2132         .isMenu = true,
2133         .buttons = button,
2134     };
2135     ShowActionMenuInner(dialogProperties, button, std::move(callback));
2136 }
2137 
ShowActionMenu(const std::string & title,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback,std::function<void (bool)> && onStatusChanged)2138 void FrontendDelegateDeclarative::ShowActionMenu(const std::string& title, const std::vector<ButtonInfo>& button,
2139     std::function<void(int32_t, int32_t)>&& callback, std::function<void(bool)>&& onStatusChanged)
2140 {
2141     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show action menu enter with status changed");
2142     DialogProperties dialogProperties = {
2143         .title = title,
2144         .autoCancel = true,
2145         .isMenu = true,
2146         .buttons = button,
2147         .onStatusChanged = std::move(onStatusChanged),
2148     };
2149     ShowActionMenuInner(dialogProperties, button, std::move(callback));
2150 }
2151 
ShowActionMenu(const PromptDialogAttr & dialogAttr,const std::vector<ButtonInfo> & buttons,std::function<void (int32_t,int32_t)> && callback)2152 void FrontendDelegateDeclarative::ShowActionMenu(const PromptDialogAttr& dialogAttr,
2153     const std::vector<ButtonInfo>& buttons, std::function<void(int32_t, int32_t)>&& callback)
2154 {
2155     TAG_LOGD(AceLogTag::ACE_OVERLAY, "show action menu enter with attr");
2156     DialogProperties dialogProperties = {
2157         .title = dialogAttr.title,
2158         .autoCancel = true,
2159         .isMenu = true,
2160         .buttons = buttons,
2161         .isShowInSubWindow = dialogAttr.showInSubWindow,
2162         .isModal = dialogAttr.isModal,
2163         .maskRect = dialogAttr.maskRect,
2164         .dialogLevelMode = dialogAttr.dialogLevelMode,
2165         .dialogLevelUniqueId = dialogAttr.dialogLevelUniqueId,
2166         .dialogImmersiveMode = dialogAttr.dialogImmersiveMode,
2167     };
2168 #if defined(PREVIEW)
2169     if (dialogProperties.isShowInSubWindow) {
2170         LOGW("[Engine Log] Unable to use the SubWindow in the Previewer. Perform this operation on the "
2171              "emulator or a real device instead.");
2172         dialogProperties.isShowInSubWindow = false;
2173     }
2174 #endif
2175     ShowActionMenuInner(dialogProperties, buttons, std::move(callback));
2176 }
2177 
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)2178 void FrontendDelegateDeclarative::EnableAlertBeforeBackPage(
2179     const std::string& message, std::function<void(int32_t)>&& callback)
2180 {
2181     if (Container::IsCurrentUseNewPipeline()) {
2182         LOGI("EnableAlertBeforeBackPage IsCurrentUseNewPipeline.");
2183         CHECK_NULL_VOID(pageRouterManager_);
2184         pageRouterManager_->EnableAlertBeforeBackPage(message, std::move(callback));
2185         return;
2186     }
2187 
2188     if (!taskExecutor_) {
2189         LOGE("task executor is null.");
2190         return;
2191     }
2192     std::unordered_map<std::string, EventMarker> callbackMarkers;
2193     auto pipelineContext = pipelineContextHolder_.Get();
2194     auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
2195     BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(successEventMarker,
2196         [weak = AceType::WeakClaim(this), callback, taskExecutor = taskExecutor_](int32_t successType) {
2197             taskExecutor->PostTask(
2198                 [weak, callback, successType]() {
2199                     callback(successType);
2200                     auto delegate = weak.Upgrade();
2201                     if (!delegate) {
2202                         return;
2203                     }
2204                     if (!successType) {
2205                         LOGI("dialog choose cancel button, can not back");
2206                         delegate->ProcessRouterTask();
2207                         return;
2208                     }
2209                     delegate->StartBack(delegate->backUri_, delegate->backParam_);
2210                 },
2211                 TaskExecutor::TaskType::JS, "ArkUIBackSuccessEvent");
2212         });
2213     callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
2214 
2215     std::lock_guard<std::mutex> lock(mutex_);
2216     if (pageRouteStack_.empty()) {
2217         LOGE("page stack is null.");
2218         return;
2219     }
2220 
2221     auto& currentPage = pageRouteStack_.back();
2222     ClearAlertCallback(currentPage);
2223     currentPage.alertCallback = callback;
2224     currentPage.dialogProperties = {
2225         .content = message,
2226         .autoCancel = false,
2227         .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
2228             { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
2229         .callbacks = std::move(callbackMarkers),
2230     };
2231 }
2232 
DisableAlertBeforeBackPage()2233 void FrontendDelegateDeclarative::DisableAlertBeforeBackPage()
2234 {
2235     if (Container::IsCurrentUseNewPipeline()) {
2236         LOGI("DisableAlertBeforeBackPage IsCurrentUseNewPipeline.");
2237         CHECK_NULL_VOID(pageRouterManager_);
2238         pageRouterManager_->DisableAlertBeforeBackPage();
2239         return;
2240     }
2241 
2242     std::lock_guard<std::mutex> lock(mutex_);
2243     if (pageRouteStack_.empty()) {
2244         LOGE("page stack is null.");
2245         return;
2246     }
2247     auto& currentPage = pageRouteStack_.back();
2248     ClearAlertCallback(currentPage);
2249     currentPage.alertCallback = nullptr;
2250 }
2251 
GetBoundingRectData(NodeId nodeId)2252 Rect FrontendDelegateDeclarative::GetBoundingRectData(NodeId nodeId)
2253 {
2254     Rect rect;
2255     auto task = [context = pipelineContextHolder_.Get(), nodeId, &rect]() {
2256         context->GetBoundingRectData(nodeId, rect);
2257     };
2258     PostSyncTaskToPage(task, "ArkUIGetBoundingRectData");
2259     return rect;
2260 }
2261 
GetInspector(NodeId nodeId)2262 std::string FrontendDelegateDeclarative::GetInspector(NodeId nodeId)
2263 {
2264     std::string attrs;
2265     auto task = [weak = WeakClaim(AceType::RawPtr(jsAccessibilityManager_)), nodeId, &attrs]() {
2266         auto accessibilityNodeManager = weak.Upgrade();
2267         if (accessibilityNodeManager) {
2268             attrs = accessibilityNodeManager->GetInspectorNodeById(nodeId);
2269         }
2270     };
2271     PostSyncTaskToPage(task, "ArkUIGetInspectorNode");
2272     return attrs;
2273 }
2274 
SetCallBackResult(const std::string & callBackId,const std::string & result)2275 void FrontendDelegateDeclarative::SetCallBackResult(const std::string& callBackId, const std::string& result)
2276 {
2277     jsCallBackResult_.try_emplace(StringToInt(callBackId), result);
2278 }
2279 
WaitTimer(const std::string & callbackId,const std::string & delay,bool isInterval,bool isFirst)2280 void FrontendDelegateDeclarative::WaitTimer(
2281     const std::string& callbackId, const std::string& delay, bool isInterval, bool isFirst)
2282 {
2283     if (!isFirst) {
2284         auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
2285         // If not find the callbackId in map, means this timer already was removed,
2286         // no need create a new cancelableTimer again.
2287         if (timeoutTaskIter == timeoutTaskMap_.end()) {
2288             return;
2289         }
2290     }
2291 
2292     int32_t delayTime = StringToInt(delay);
2293     // CancelableCallback class can only be executed once.
2294     CancelableCallback<void()> cancelableTimer;
2295     cancelableTimer.Reset([callbackId, delay, isInterval, call = timer_] { call(callbackId, delay, isInterval); });
2296     auto result = timeoutTaskMap_.try_emplace(callbackId, cancelableTimer);
2297     if (!result.second) {
2298         result.first->second = cancelableTimer;
2299     }
2300     taskExecutor_->PostDelayedTask(cancelableTimer, TaskExecutor::TaskType::JS, delayTime, "ArkUIWaitTimer");
2301 }
2302 
ClearTimer(const std::string & callbackId)2303 void FrontendDelegateDeclarative::ClearTimer(const std::string& callbackId)
2304 {
2305     auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
2306     if (timeoutTaskIter != timeoutTaskMap_.end()) {
2307         timeoutTaskIter->second.Cancel();
2308         timeoutTaskMap_.erase(timeoutTaskIter);
2309     } else {
2310         LOGW("ClearTimer callbackId not found");
2311     }
2312 }
2313 
PostSyncTaskToPage(std::function<void ()> && task,const std::string & name)2314 void FrontendDelegateDeclarative::PostSyncTaskToPage(std::function<void()>&& task, const std::string& name)
2315 {
2316     pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
2317     taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::UI, name);
2318 }
2319 
AddTaskObserver(std::function<void ()> && task)2320 void FrontendDelegateDeclarative::AddTaskObserver(std::function<void()>&& task)
2321 {
2322     taskExecutor_->AddTaskObserver(std::move(task));
2323 }
2324 
RemoveTaskObserver()2325 void FrontendDelegateDeclarative::RemoveTaskObserver()
2326 {
2327     taskExecutor_->RemoveTaskObserver();
2328 }
2329 
GetAssetContent(const std::string & url,std::string & content)2330 bool FrontendDelegateDeclarative::GetAssetContent(const std::string& url, std::string& content)
2331 {
2332     return GetAssetContentImpl(assetManager_, url, content);
2333 }
2334 
GetAssetContent(const std::string & url,std::vector<uint8_t> & content)2335 bool FrontendDelegateDeclarative::GetAssetContent(const std::string& url, std::vector<uint8_t>& content)
2336 {
2337     return GetAssetContentImpl(assetManager_, url, content);
2338 }
2339 
GetAssetPath(const std::string & url)2340 std::string FrontendDelegateDeclarative::GetAssetPath(const std::string& url)
2341 {
2342     return GetAssetPathImpl(assetManager_, url);
2343 }
2344 
LoadPage(int32_t pageId,const PageTarget & target,bool isMainPage,const std::string & params,bool isRestore)2345 UIContentErrorCode FrontendDelegateDeclarative::LoadPage(
2346     int32_t pageId, const PageTarget& target, bool isMainPage, const std::string& params, bool isRestore)
2347 {
2348     LOGI("LoadPage[%{public}d]: %{public}s.", pageId, target.url.c_str());
2349     if (pageId == INVALID_PAGE_ID) {
2350         LOGE("FrontendDelegateDeclarative, invalid page id");
2351         EventReport::SendPageRouterException(PageRouterExcepType::LOAD_PAGE_ERR, target.url);
2352         ProcessRouterTask();
2353         return UIContentErrorCode::INVALID_PAGE_ID;
2354     }
2355     {
2356         std::lock_guard<std::mutex> lock(mutex_);
2357         pageId_ = pageId;
2358         pageParamMap_[pageId] = params;
2359     }
2360     if (isStagingPageExist_) {
2361         LOGE("FrontendDelegateDeclarative, load page failed, waiting for current page loading finish.");
2362         RecyclePageId(pageId);
2363         ProcessRouterTask();
2364         return UIContentErrorCode::STAGING_PAGE_EXIST;
2365     }
2366     isStagingPageExist_ = true;
2367 
2368     singlePageId_ = INVALID_PAGE_ID;
2369     if (target.routerMode == RouterMode::SINGLE) {
2370         singlePageId_ = GetPageIdByUrl(target.url);
2371         LOGI("single page id = %{public}d", singlePageId_);
2372     }
2373 
2374     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
2375     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
2376     page->SetPageParams(params);
2377     page->SetFlushCallback([weak = AceType::WeakClaim(this), isMainPage, isRestore](const RefPtr<JsAcePage>& acePage) {
2378         auto delegate = weak.Upgrade();
2379         if (!delegate) {
2380             return;
2381         }
2382         if (acePage) {
2383             delegate->FlushPageCommand(acePage, acePage->GetUrl(), isMainPage, isRestore);
2384         } else {
2385             LOGE("flush callback called unexpected");
2386             delegate->ProcessRouterTask();
2387         }
2388     });
2389     taskExecutor_->PostTask(
2390         [weak = AceType::WeakClaim(this), page, isMainPage] {
2391             auto delegate = weak.Upgrade();
2392             if (!delegate) {
2393                 return;
2394             }
2395             delegate->loadJs_(page->GetUrl(), page, isMainPage);
2396             page->FlushCommands();
2397             // just make sure the pipelineContext is created.
2398             auto pipeline = delegate->pipelineContextHolder_.Get();
2399             if (delegate->GetMinPlatformVersion() > 0) {
2400                 pipeline->SetMinPlatformVersion(delegate->GetMinPlatformVersion());
2401             }
2402             delegate->taskExecutor_->PostTask(
2403                 [weak, page] {
2404                     auto delegate = weak.Upgrade();
2405                     if (delegate) {
2406                         auto context = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
2407                         if (context) {
2408                             context->FlushFocus();
2409                         }
2410                     }
2411                     if (page->GetDomDocument()) {
2412                         page->GetDomDocument()->HandlePageLoadFinish();
2413                     }
2414                 },
2415                 TaskExecutor::TaskType::UI, "ArkUIPageLoadFinish");
2416         },
2417         TaskExecutor::TaskType::JS, "ArkUILoadJsPage");
2418 
2419     return UIContentErrorCode::NO_ERRORS;
2420 }
2421 
OnSurfaceChanged()2422 void FrontendDelegateDeclarative::OnSurfaceChanged()
2423 {
2424     if (mediaQueryInfo_->GetIsInit()) {
2425         mediaQueryInfo_->SetIsInit(false);
2426     }
2427     mediaQueryInfo_->EnsureListenerIdValid();
2428     OnMediaQueryUpdate(true);
2429 }
2430 
OnMediaQueryUpdate(bool isSynchronous)2431 void FrontendDelegateDeclarative::OnMediaQueryUpdate(bool isSynchronous)
2432 {
2433     auto containerId = Container::CurrentId();
2434     if (containerId < 0) {
2435         auto container = Container::GetActive();
2436         if (container) {
2437             containerId = container->GetInstanceId();
2438         }
2439     }
2440     bool isInSubwindow = containerId >= 1000000;
2441     if (isInSubwindow) {
2442         return;
2443     }
2444     if (mediaQueryInfo_->GetIsInit()) {
2445         return;
2446     }
2447 
2448     auto callback = [weak = AceType::WeakClaim(this)] {
2449         auto delegate = weak.Upgrade();
2450         if (!delegate) {
2451             return;
2452         }
2453         const auto& info = delegate->mediaQueryInfo_->GetMediaQueryInfo();
2454         // request css mediaquery
2455         std::string param("\"viewsizechanged\",");
2456         param.append(info);
2457         delegate->asyncEvent_("_root", param);
2458 
2459         // request js media query
2460         const auto& listenerId = delegate->mediaQueryInfo_->GetListenerId();
2461         delegate->mediaQueryCallback_(listenerId, info);
2462         delegate->mediaQueryInfo_->ResetListenerId();
2463     };
2464     auto container = Container::Current();
2465     if (container && container->IsUseStageModel() && isSynchronous) {
2466         callback();
2467         return;
2468     }
2469     taskExecutor_->PostTask(callback, TaskExecutor::TaskType::JS, "ArkUIMediaQueryUpdate");
2470 }
2471 
OnLayoutCompleted(const std::string & componentId)2472 void FrontendDelegateDeclarative::OnLayoutCompleted(const std::string& componentId)
2473 {
2474     auto engine = EngineHelper::GetCurrentEngine();
2475     CHECK_NULL_VOID(engine);
2476     if (!engine->IsLayoutCallBackFuncExist(componentId)) {
2477         return;
2478     }
2479 
2480     taskExecutor_->PostTask(
2481         [weak = AceType::WeakClaim(this), componentId] {
2482             auto delegate = weak.Upgrade();
2483             if (!delegate) {
2484                 return;
2485             }
2486             delegate->layoutInspectorCallback_(componentId);
2487         },
2488         TaskExecutor::TaskType::JS, "ArkUIInspectorLayoutCompleted");
2489 }
2490 
OnDrawCompleted(const std::string & componentId)2491 void FrontendDelegateDeclarative::OnDrawCompleted(const std::string& componentId)
2492 {
2493     auto engine = EngineHelper::GetCurrentEngine();
2494     CHECK_NULL_VOID(engine);
2495     if (!engine->IsDrawCallBackFuncExist(componentId)) {
2496         return;
2497     }
2498 
2499     taskExecutor_->PostTask(
2500         [weak = AceType::WeakClaim(this), componentId] {
2501             auto delegate = weak.Upgrade();
2502             if (!delegate) {
2503                 return;
2504             }
2505             delegate->drawInspectorCallback_(componentId);
2506         },
2507         TaskExecutor::TaskType::JS, "ArkUIInspectorDrawCompleted");
2508 }
2509 
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage,bool isRestore)2510 void FrontendDelegateDeclarative::OnPageReady(
2511     const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage, bool isRestore)
2512 {
2513     LOGI("OnPageReady url = %{private}s", url.c_str());
2514     // Pop all JS command and execute them in UI thread.
2515     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
2516     page->PopAllCommands(*jsCommands);
2517 
2518     auto pipelineContext = pipelineContextHolder_.Get();
2519     page->SetPipelineContext(pipelineContext);
2520     taskExecutor_->PostTask(
2521         [weak = AceType::WeakClaim(this), page, url, jsCommands, isMainPage, isRestore] {
2522             auto delegate = weak.Upgrade();
2523             if (!delegate) {
2524                 return;
2525             }
2526             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
2527             CHECK_NULL_VOID(pipelineContext);
2528             // Flush all JS commands.
2529             for (const auto& command : *jsCommands) {
2530                 command->Execute(page);
2531             }
2532             // Just clear all dirty nodes.
2533             page->ClearAllDirtyNodes();
2534             if (page->GetDomDocument()) {
2535                 page->GetDomDocument()->HandleComponentPostBinding();
2536             }
2537             if (pipelineContext->GetAccessibilityManager()) {
2538                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
2539             }
2540             if (isRestore) {
2541                 delegate->RestorePopPage(page, url);
2542                 return;
2543             }
2544             if (pipelineContext->CanPushPage()) {
2545                 if (!isMainPage) {
2546                     delegate->OnPageHide();
2547                 }
2548                 delegate->OnPrePageChange(page);
2549                 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
2550                 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
2551                     [weak, page](
2552                         const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
2553                         auto delegate = weak.Upgrade();
2554                         if (delegate) {
2555                             delegate->PushPageTransitionListener(event, page);
2556                         }
2557                     });
2558                 if (delegate->singlePageId_ != INVALID_PAGE_ID) {
2559                     pipelineContext->SetSinglePageId(delegate->singlePageId_);
2560                 }
2561                 pipelineContext->PushPage(page->BuildPage(url), page->GetStageElement());
2562             } else {
2563                 // This page has been loaded but become useless now, the corresponding js instance
2564                 // must be destroyed to avoid memory leak.
2565                 LOGW("router push run in unexpected process");
2566                 delegate->OnPageDestroy(page->GetPageId());
2567                 delegate->ResetStagingPage();
2568                 delegate->ProcessRouterTask();
2569             }
2570             delegate->isStagingPageExist_ = false;
2571         },
2572         TaskExecutor::TaskType::UI, "ArkUIPageReady");
2573 }
2574 
PushPageTransitionListener(const TransitionEvent & event,const RefPtr<JsAcePage> & page)2575 void FrontendDelegateDeclarative::PushPageTransitionListener(
2576     const TransitionEvent& event, const RefPtr<JsAcePage>& page)
2577 {
2578     if (event == TransitionEvent::PUSH_END) {
2579         OnPushPageSuccess(page, page->GetUrl());
2580         SetCurrentPage(page->GetPageId());
2581         OnPageShow();
2582         OnMediaQueryUpdate();
2583         ProcessRouterTask();
2584     }
2585 }
2586 
OnPushPageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)2587 void FrontendDelegateDeclarative::OnPushPageSuccess(const RefPtr<JsAcePage>& page, const std::string& url)
2588 {
2589     std::lock_guard<std::mutex> lock(mutex_);
2590     AddPageLocked(page);
2591     PageInfo pageInfo;
2592     pageInfo.pageId = page->GetPageId();
2593     pageInfo.url = page->GetUrl();
2594     pageRouteStack_.emplace_back(pageInfo);
2595     if (singlePageId_ != INVALID_PAGE_ID) {
2596         RecycleSinglePage();
2597     }
2598     if (pageRouteStack_.size() >= MAX_ROUTER_STACK) {
2599         isRouteStackFull_ = true;
2600         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, page->GetUrl());
2601     }
2602     LOGI("OnPushPageSuccess size=%{private}zu,pageId=%{private}d,url=%{private}s", pageRouteStack_.size(),
2603         pageRouteStack_.back().pageId, pageRouteStack_.back().url.c_str());
2604 }
2605 
RecycleSinglePage()2606 void FrontendDelegateDeclarative::RecycleSinglePage()
2607 {
2608     LOGI("single page recycle");
2609     auto iter = find_if(pageRouteStack_.begin(), pageRouteStack_.end(),
2610         [&](const PageInfo& item) { return item.pageId == singlePageId_; });
2611     if (iter != pageRouteStack_.end()) {
2612         pageMap_.erase(singlePageId_);
2613         pageParamMap_.erase(singlePageId_);
2614         pageRouteStack_.erase(iter);
2615         OnPageDestroy(singlePageId_);
2616     }
2617     singlePageId_ = INVALID_PAGE_ID;
2618 }
2619 
OnPrePageChange(const RefPtr<JsAcePage> & page)2620 void FrontendDelegateDeclarative::OnPrePageChange(const RefPtr<JsAcePage>& page)
2621 {
2622     if (page && page->GetDomDocument() && jsAccessibilityManager_) {
2623         jsAccessibilityManager_->SetRootNodeId(page->GetDomDocument()->GetRootNodeId());
2624     }
2625 }
2626 
FlushPageCommand(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage,bool isRestore)2627 void FrontendDelegateDeclarative::FlushPageCommand(
2628     const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage, bool isRestore)
2629 {
2630     if (!page) {
2631         ProcessRouterTask();
2632         return;
2633     }
2634     if (page->FragmentCount() == 1) {
2635         OnPageReady(page, url, isMainPage, isRestore);
2636     } else {
2637         TriggerPageUpdate(page->GetPageId());
2638     }
2639 }
2640 
AddPageLocked(const RefPtr<JsAcePage> & page)2641 void FrontendDelegateDeclarative::AddPageLocked(const RefPtr<JsAcePage>& page)
2642 {
2643     auto result = pageMap_.try_emplace(page->GetPageId(), page);
2644     if (!result.second) {
2645         LOGW("the page has already in the map");
2646     }
2647 }
2648 
SetCurrentPage(int32_t pageId)2649 void FrontendDelegateDeclarative::SetCurrentPage(int32_t pageId)
2650 {
2651     auto page = GetPage(pageId);
2652     if (page != nullptr) {
2653         jsAccessibilityManager_->SetVersion(AccessibilityVersion::JS_DECLARATIVE_VERSION);
2654         jsAccessibilityManager_->SetRunningPage(page);
2655         taskExecutor_->PostTask([updatePage = updatePage_, page] { updatePage(page); },
2656             TaskExecutor::TaskType::JS, "ArkUISetCurrentPage");
2657     } else {
2658         LOGE("FrontendDelegateDeclarative SetCurrentPage page is null.");
2659     }
2660 }
2661 
PopToPage(const std::string & url)2662 void FrontendDelegateDeclarative::PopToPage(const std::string& url)
2663 {
2664     taskExecutor_->PostTask(
2665         [weak = AceType::WeakClaim(this), url] {
2666             auto delegate = weak.Upgrade();
2667             if (!delegate) {
2668                 return;
2669             }
2670             auto pageId = delegate->GetPageIdByUrl(url);
2671             if (pageId == INVALID_PAGE_ID) {
2672                 delegate->ProcessRouterTask();
2673                 return;
2674             }
2675             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
2676             CHECK_NULL_VOID(pipelineContext);
2677             if (!pipelineContext->CanPopPage()) {
2678                 LOGW("router pop to page run in unexpected process");
2679                 delegate->ResetStagingPage();
2680                 delegate->ProcessRouterTask();
2681                 return;
2682             }
2683             delegate->OnPageHide();
2684             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
2685             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
2686                 [weak, url, pageId](
2687                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
2688                     auto delegate = weak.Upgrade();
2689                     if (delegate) {
2690                         delegate->PopToPageTransitionListener(event, url, pageId);
2691                     }
2692                 });
2693             pipelineContext->PopToPage(pageId);
2694         },
2695         TaskExecutor::TaskType::UI, "ArkUIPopToPage");
2696 }
2697 
PopToPageTransitionListener(const TransitionEvent & event,const std::string & url,int32_t pageId)2698 void FrontendDelegateDeclarative::PopToPageTransitionListener(
2699     const TransitionEvent& event, const std::string& url, int32_t pageId)
2700 {
2701     if (event == TransitionEvent::POP_END) {
2702         OnPopToPageSuccess(url);
2703         SetCurrentPage(pageId);
2704         OnPageShow();
2705         OnMediaQueryUpdate();
2706         ProcessRouterTask();
2707     }
2708 }
2709 
OnPopToPageSuccess(const std::string & url)2710 void FrontendDelegateDeclarative::OnPopToPageSuccess(const std::string& url)
2711 {
2712     std::lock_guard<std::mutex> lock(mutex_);
2713     while (!pageRouteStack_.empty()) {
2714         if (pageRouteStack_.back().url == url) {
2715             break;
2716         }
2717         OnPageDestroy(pageRouteStack_.back().pageId);
2718         pageMap_.erase(pageRouteStack_.back().pageId);
2719         pageParamMap_.erase(pageRouteStack_.back().pageId);
2720         ClearAlertCallback(pageRouteStack_.back());
2721         pageRouteStack_.pop_back();
2722     }
2723 
2724     if (isRouteStackFull_) {
2725         isRouteStackFull_ = false;
2726     }
2727 }
2728 
OnPopPageSuccess()2729 int32_t FrontendDelegateDeclarative::OnPopPageSuccess()
2730 {
2731     std::lock_guard<std::mutex> lock(mutex_);
2732     pageMap_.erase(pageRouteStack_.back().pageId);
2733     pageParamMap_.erase(pageRouteStack_.back().pageId);
2734     ClearAlertCallback(pageRouteStack_.back());
2735     pageRouteStack_.pop_back();
2736     if (isRouteStackFull_) {
2737         isRouteStackFull_ = false;
2738     }
2739     if (!pageRouteStack_.empty()) {
2740         LOGI("OnPopPageSuccess: pop to page %{private}s", pageRouteStack_.back().url.c_str());
2741         return pageRouteStack_.back().pageId;
2742     }
2743     return INVALID_PAGE_ID;
2744 }
2745 
PopPage()2746 void FrontendDelegateDeclarative::PopPage()
2747 {
2748     taskExecutor_->PostTask(
2749         [weak = AceType::WeakClaim(this)] {
2750             auto delegate = weak.Upgrade();
2751             if (!delegate) {
2752                 return;
2753             }
2754             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
2755             CHECK_NULL_VOID(pipelineContext);
2756             if (delegate->GetStackSize() == 1) {
2757                 if (delegate->disallowPopLastPage_) {
2758                     LOGW("Not allow back because this is the last page!");
2759                     delegate->ProcessRouterTask();
2760                     return;
2761                 }
2762                 delegate->OnPageHide();
2763                 delegate->OnPageDestroy(delegate->GetRunningPageId());
2764                 delegate->OnPopPageSuccess();
2765                 pipelineContext->Finish();
2766                 return;
2767             }
2768             if (!pipelineContext->CanPopPage()) {
2769                 delegate->ResetStagingPage();
2770                 LOGW("router pop run in unexpected process");
2771                 delegate->ProcessRouterTask();
2772                 return;
2773             }
2774             delegate->OnPageHide();
2775             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
2776             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
2777                 [weak, destroyPageId = delegate->GetRunningPageId()](
2778                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
2779                     auto delegate = weak.Upgrade();
2780                     if (delegate) {
2781                         delegate->PopPageTransitionListener(event, destroyPageId);
2782                     }
2783                 });
2784             pipelineContext->PopPage();
2785         },
2786         TaskExecutor::TaskType::UI, "ArkUIPopPage");
2787 }
2788 
PopPageTransitionListener(const TransitionEvent & event,int32_t destroyPageId)2789 void FrontendDelegateDeclarative::PopPageTransitionListener(const TransitionEvent& event, int32_t destroyPageId)
2790 {
2791     if (event == TransitionEvent::POP_END) {
2792         OnPageDestroy(destroyPageId);
2793         auto pageId = OnPopPageSuccess();
2794         SetCurrentPage(pageId);
2795         OnPageShow();
2796         OnMediaQueryUpdate();
2797         ProcessRouterTask();
2798     }
2799 }
2800 
RestorePopPage(const RefPtr<JsAcePage> & page,const std::string & url)2801 void FrontendDelegateDeclarative::RestorePopPage(const RefPtr<JsAcePage>& page, const std::string& url)
2802 {
2803     taskExecutor_->PostTask(
2804         [weak = AceType::WeakClaim(this), page, url] {
2805             auto delegate = weak.Upgrade();
2806             if (!delegate) {
2807                 return;
2808             }
2809             LOGI("RestorePopPage begin");
2810             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
2811             CHECK_NULL_VOID(pipelineContext);
2812             if (delegate->GetStackSize() == 1) {
2813                 if (delegate->disallowPopLastPage_) {
2814                     LOGW("Not allow back because this is the last page!");
2815                     delegate->ProcessRouterTask();
2816                     return;
2817                 }
2818                 delegate->OnPageHide();
2819                 delegate->OnPageDestroy(delegate->GetRunningPageId());
2820                 delegate->OnPopPageSuccess();
2821                 pipelineContext->Finish();
2822                 return;
2823             }
2824             delegate->OnPageHide();
2825             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
2826             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
2827                 [weak, url, page](
2828                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
2829                     auto delegate = weak.Upgrade();
2830                     if (delegate) {
2831                         delegate->RestorePageTransitionListener(event, url, page);
2832                     }
2833                 });
2834             pipelineContext->RestorePopPage(page->BuildPage(url));
2835             delegate->isStagingPageExist_ = false;
2836         },
2837         TaskExecutor::TaskType::UI, "ArkUIRestorePopPage");
2838 }
2839 
RestorePageTransitionListener(const TransitionEvent & event,const std::string & url,const RefPtr<JsAcePage> & page)2840 void FrontendDelegateDeclarative::RestorePageTransitionListener(
2841     const TransitionEvent& event, const std::string& url, const RefPtr<JsAcePage>& page)
2842 {
2843     if (event == TransitionEvent::PUSH_END) {
2844         LOGI("RestorePageTransitionListener %{public}s", url.c_str());
2845         OnPopToPageSuccess(url);
2846         {
2847             std::lock_guard<std::mutex> lock(mutex_);
2848             AddPageLocked(page);
2849             pageRouteStack_.back().isRestore = false;
2850         }
2851         SetCurrentPage(GetPageIdByUrl(url));
2852         OnPageShow();
2853         OnMediaQueryUpdate();
2854         ProcessRouterTask();
2855     }
2856 }
2857 
OnClearInvisiblePagesSuccess()2858 int32_t FrontendDelegateDeclarative::OnClearInvisiblePagesSuccess()
2859 {
2860     std::lock_guard<std::mutex> lock(mutex_);
2861     PageInfo pageInfo = std::move(pageRouteStack_.back());
2862     pageRouteStack_.pop_back();
2863     for (const auto& info : pageRouteStack_) {
2864         ClearAlertCallback(info);
2865         OnPageDestroy(info.pageId);
2866         pageMap_.erase(info.pageId);
2867         pageParamMap_.erase(info.pageId);
2868     }
2869     pageRouteStack_.clear();
2870     int32_t resPageId = pageInfo.pageId;
2871     pageRouteStack_.emplace_back(std::move(pageInfo));
2872     if (isRouteStackFull_) {
2873         isRouteStackFull_ = false;
2874     }
2875     return resPageId;
2876 }
2877 
ClearInvisiblePages()2878 void FrontendDelegateDeclarative::ClearInvisiblePages()
2879 {
2880     taskExecutor_->PostTask(
2881         [weak = AceType::WeakClaim(this)] {
2882             auto delegate = weak.Upgrade();
2883             if (!delegate) {
2884                 return;
2885             }
2886             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
2887             CHECK_NULL_VOID(pipelineContext);
2888             if (pipelineContext->ClearInvisiblePages([weak]() {
2889                     auto delegate = weak.Upgrade();
2890                     if (!delegate) {
2891                         return;
2892                     }
2893                     delegate->ProcessRouterTask();
2894                 })) {
2895                 auto pageId = delegate->OnClearInvisiblePagesSuccess();
2896                 delegate->SetCurrentPage(pageId);
2897             } else {
2898                 delegate->ProcessRouterTask();
2899             }
2900         },
2901         TaskExecutor::TaskType::UI, "ArkUIClearInvisiblePages");
2902 }
2903 
OnReplacePageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)2904 void FrontendDelegateDeclarative::OnReplacePageSuccess(const RefPtr<JsAcePage>& page, const std::string& url)
2905 {
2906     if (!page) {
2907         return;
2908     }
2909     std::lock_guard<std::mutex> lock(mutex_);
2910     AddPageLocked(page);
2911     if (!pageRouteStack_.empty()) {
2912         pageMap_.erase(pageRouteStack_.back().pageId);
2913         pageParamMap_.erase(pageRouteStack_.back().pageId);
2914         ClearAlertCallback(pageRouteStack_.back());
2915         pageRouteStack_.pop_back();
2916     }
2917     PageInfo pageInfo;
2918     pageInfo.pageId = page->GetPageId();
2919     pageInfo.url = url;
2920     pageRouteStack_.emplace_back(pageInfo);
2921     if (singlePageId_ != INVALID_PAGE_ID) {
2922         RecycleSinglePage();
2923     }
2924 }
2925 
ReplacePage(const RefPtr<JsAcePage> & page,const std::string & url)2926 void FrontendDelegateDeclarative::ReplacePage(const RefPtr<JsAcePage>& page, const std::string& url)
2927 {
2928     LOGI("ReplacePage url = %{private}s", url.c_str());
2929     // Pop all JS command and execute them in UI thread.
2930     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
2931     page->PopAllCommands(*jsCommands);
2932 
2933     auto pipelineContext = pipelineContextHolder_.Get();
2934     page->SetPipelineContext(pipelineContext);
2935     taskExecutor_->PostTask(
2936         [weak = AceType::WeakClaim(this), page, url, jsCommands] {
2937             auto delegate = weak.Upgrade();
2938             if (!delegate) {
2939                 return;
2940             }
2941             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
2942             CHECK_NULL_VOID(pipelineContext);
2943             // Flush all JS commands.
2944             for (const auto& command : *jsCommands) {
2945                 command->Execute(page);
2946             }
2947             // Just clear all dirty nodes.
2948             page->ClearAllDirtyNodes();
2949             page->GetDomDocument()->HandleComponentPostBinding();
2950             pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
2951             if (pipelineContext->CanReplacePage()) {
2952                 delegate->OnPageHide();
2953                 delegate->OnPageDestroy(delegate->GetRunningPageId());
2954                 delegate->OnPrePageChange(page);
2955                 if (delegate->singlePageId_ != INVALID_PAGE_ID) {
2956                     pipelineContext->SetSinglePageId(delegate->singlePageId_);
2957                 }
2958                 pipelineContext->ReplacePage(page->BuildPage(url), page->GetStageElement(), [weak, page, url]() {
2959                     auto delegate = weak.Upgrade();
2960                     if (!delegate) {
2961                         return;
2962                     }
2963                     delegate->OnReplacePageSuccess(page, url);
2964                     delegate->SetCurrentPage(page->GetPageId());
2965                     delegate->OnPageShow();
2966                     delegate->OnMediaQueryUpdate();
2967                     delegate->ProcessRouterTask();
2968                 });
2969             } else {
2970                 // This page has been loaded but become useless now, the corresponding js instance
2971                 // must be destroyed to avoid memory leak.
2972                 LOGW("replace run in unexpected process");
2973                 delegate->OnPageDestroy(page->GetPageId());
2974                 delegate->ResetStagingPage();
2975                 delegate->ProcessRouterTask();
2976             }
2977             delegate->isStagingPageExist_ = false;
2978         },
2979         TaskExecutor::TaskType::UI, "ArkUIReplacePage");
2980 }
2981 
ReplacePageInSubStage(const RefPtr<JsAcePage> & page,const std::string & url)2982 void FrontendDelegateDeclarative::ReplacePageInSubStage(const RefPtr<JsAcePage>& page, const std::string& url)
2983 {
2984     LOGI("ReplacePageInSubStage url = %{private}s", url.c_str());
2985     auto pipelineContext = pipelineContextHolder_.Get();
2986     page->SetPipelineContext(pipelineContext);
2987     taskExecutor_->PostTask(
2988         [weak = AceType::WeakClaim(this), page, url] {
2989             auto delegate = weak.Upgrade();
2990             if (!delegate) {
2991                 return;
2992             }
2993             auto pipelineContext = AceType::DynamicCast<PipelineContext>(page->GetPipelineContext().Upgrade());
2994             if (!pipelineContext) {
2995                 LOGE("pipelineContext is null");
2996                 return;
2997             }
2998             auto stageElement = page->GetStageElement();
2999             if (!stageElement) {
3000                 LOGE("stageElement is null");
3001                 return;
3002             }
3003 
3004             if (stageElement->GetChildren().empty()) {
3005                 delegate->OnPrePageChange(page);
3006                 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
3007                 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
3008                     [weak, page](
3009                         const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
3010                         auto delegate = weak.Upgrade();
3011                         if (delegate) {
3012                             delegate->PushPageTransitionListener(event, page);
3013                         }
3014                     });
3015                 pipelineContext->PushPage(page->BuildPage(url), page->GetStageElement());
3016                 delegate->isStagingPageExist_ = false;
3017                 return;
3018             }
3019 
3020             if (stageElement->CanReplacePage()) {
3021                 delegate->OnPageHide();
3022                 delegate->OnPageDestroy(delegate->GetRunningPageId());
3023                 delegate->OnPrePageChange(page);
3024                 stageElement->Replace(page->BuildPage(url), [weak, page, url]() {
3025                     auto delegate = weak.Upgrade();
3026                     if (!delegate) {
3027                         return;
3028                     }
3029                     delegate->OnReplacePageSuccess(page, url);
3030                     delegate->SetCurrentPage(page->GetPageId());
3031                     delegate->OnPageShow();
3032                     delegate->OnMediaQueryUpdate();
3033                     delegate->ProcessRouterTask();
3034                 });
3035             } else {
3036                 // This page has been loaded but become useless now, the corresponding js instance
3037                 // must be destroyed to avoid memory leak.
3038                 LOGW("replace run in unexpected process");
3039                 delegate->OnPageDestroy(page->GetPageId());
3040                 delegate->ResetStagingPage();
3041                 delegate->ProcessRouterTask();
3042             }
3043             delegate->isStagingPageExist_ = false;
3044         },
3045         TaskExecutor::TaskType::UI, "ArkUIReplacePageInSubStage");
3046 }
3047 
GetEffectiveContainerId() const3048 std::optional<int32_t> FrontendDelegateDeclarative::GetEffectiveContainerId() const
3049 {
3050     std::optional<int32_t> id;
3051     auto currentId = Container::CurrentId();
3052     auto container = Container::GetContainer(currentId);
3053     CHECK_NULL_RETURN(container, id);
3054     if (container->IsSubContainer()) {
3055         currentId = SubwindowManager::GetInstance()->GetParentContainerId(currentId);
3056     }
3057     if (currentId != -1) {
3058         id.emplace(currentId);
3059     }
3060     return id;
3061 }
3062 
LoadReplacePage(int32_t pageId,const PageTarget & target,const std::string & params)3063 void FrontendDelegateDeclarative::LoadReplacePage(int32_t pageId, const PageTarget& target, const std::string& params)
3064 {
3065     LOGI("FrontendDelegateDeclarative LoadReplacePage[%{private}d]: %{private}s.", pageId, target.url.c_str());
3066     if (pageId == INVALID_PAGE_ID) {
3067         LOGW("FrontendDelegateDeclarative, invalid page id");
3068         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, target.url);
3069         ProcessRouterTask();
3070         return;
3071     }
3072     {
3073         std::lock_guard<std::mutex> lock(mutex_);
3074         pageId_ = pageId;
3075         pageParamMap_[pageId] = params;
3076     }
3077     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
3078     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
3079     page->SetSubStage(target.useSubStage);
3080     if (isStagingPageExist_ && !page->GetSubStageFlag()) {
3081         LOGW("FrontendDelegateDeclarative, replace page failed, waiting for current page loading finish.");
3082         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, target.url);
3083         ProcessRouterTask();
3084         return;
3085     }
3086 
3087     singlePageId_ = INVALID_PAGE_ID;
3088     if (target.routerMode == RouterMode::SINGLE) {
3089         singlePageId_ = GetPageIdByUrl(target.url);
3090         LOGI("single page id = %{public}d", singlePageId_);
3091     }
3092 
3093     isStagingPageExist_ = true;
3094     page->SetPageParams(params);
3095     taskExecutor_->PostTask(
3096         [page, weak = AceType::WeakClaim(this)] {
3097             auto delegate = weak.Upgrade();
3098             if (delegate) {
3099                 delegate->loadJs_(page->GetUrl(), page, false);
3100                 if (page->GetSubStageFlag()) {
3101                     page->FireDeclarativeOnPageAppearCallback();
3102                     delegate->ReplacePageInSubStage(page, page->GetUrl());
3103                 } else {
3104                     delegate->ReplacePage(page, page->GetUrl());
3105                 }
3106             }
3107         },
3108         TaskExecutor::TaskType::JS, "ArkUILoadReplacePage");
3109 }
3110 
SetColorMode(ColorMode colorMode)3111 void FrontendDelegateDeclarative::SetColorMode(ColorMode colorMode)
3112 {
3113     OnMediaQueryUpdate();
3114 }
3115 
RebuildAllPages()3116 void FrontendDelegateDeclarative::RebuildAllPages()
3117 {
3118     if (Container::IsCurrentUseNewPipeline()) {
3119         CHECK_NULL_VOID(pageRouterManager_);
3120         auto url = pageRouterManager_->GetCurrentPageUrl();
3121         pageRouterManager_->Clear();
3122         pageRouterManager_->RunPage(url, "");
3123         return;
3124     }
3125     std::unordered_map<int32_t, RefPtr<JsAcePage>> pages;
3126     {
3127         std::lock_guard<std::mutex> lock(mutex_);
3128         pages.insert(pageMap_.begin(), pageMap_.end());
3129     }
3130     for (const auto& [pageId, page] : pages) {
3131         page->FireDeclarativeOnPageRefreshCallback();
3132         TriggerPageUpdate(page->GetPageId(), true);
3133     }
3134 }
3135 
OnPageShow(bool isFromWindow)3136 void FrontendDelegateDeclarative::OnPageShow(bool isFromWindow)
3137 {
3138     auto task = [weak = AceType::WeakClaim(this), isFromWindow] {
3139         auto delegate = weak.Upgrade();
3140         CHECK_NULL_VOID(delegate);
3141         if (Container::IsCurrentUseNewPipeline()) {
3142             auto pageRouterManager = delegate->GetPageRouterManager();
3143             CHECK_NULL_VOID(pageRouterManager);
3144             auto pageNode = pageRouterManager->GetCurrentPageNode();
3145             CHECK_NULL_VOID(pageNode);
3146             auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
3147             CHECK_NULL_VOID(pagePattern);
3148             pagePattern->OnShow(isFromWindow);
3149             return;
3150         }
3151 
3152         auto pageId = delegate->GetRunningPageId();
3153         auto page = delegate->GetPage(pageId);
3154         if (page) {
3155             page->FireDeclarativeOnPageAppearCallback();
3156         }
3157     };
3158 
3159     if (taskExecutor_->WillRunOnCurrentThread(TaskExecutor::TaskType::JS)) {
3160         task();
3161         FireSyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
3162         return;
3163     } else {
3164         taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS, "ArkUIPageShow");
3165         FireAsyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
3166     }
3167 }
3168 
OnPageHide(bool isFromWindow)3169 void FrontendDelegateDeclarative::OnPageHide(bool isFromWindow)
3170 {
3171     auto task = [weak = AceType::WeakClaim(this), isFromWindow] {
3172         auto delegate = weak.Upgrade();
3173         CHECK_NULL_VOID(delegate);
3174         if (Container::IsCurrentUseNewPipeline()) {
3175             auto pageRouterManager = delegate->GetPageRouterManager();
3176             CHECK_NULL_VOID(pageRouterManager);
3177             auto pageNode = pageRouterManager->GetCurrentPageNode();
3178             CHECK_NULL_VOID(pageNode);
3179             auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
3180             CHECK_NULL_VOID(pagePattern);
3181             pagePattern->OnHide(isFromWindow);
3182             return;
3183         }
3184 
3185         auto pageId = delegate->GetRunningPageId();
3186         auto page = delegate->GetPage(pageId);
3187         if (page) {
3188             page->FireDeclarativeOnPageDisAppearCallback();
3189         }
3190     };
3191 
3192     if (taskExecutor_->WillRunOnCurrentThread(TaskExecutor::TaskType::JS)) {
3193         task();
3194         FireSyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
3195     } else {
3196         taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS, "ArkUIPageHide");
3197         FireAsyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
3198     }
3199 }
3200 
ClearAlertCallback(PageInfo pageInfo)3201 void FrontendDelegateDeclarative::ClearAlertCallback(PageInfo pageInfo)
3202 {
3203     if (pageInfo.alertCallback) {
3204         // notify to clear js reference
3205         pageInfo.alertCallback(static_cast<int32_t>(AlertState::RECOVERY));
3206         pageInfo.alertCallback = nullptr;
3207     }
3208 }
3209 
OnPageDestroy(int32_t pageId)3210 void FrontendDelegateDeclarative::OnPageDestroy(int32_t pageId)
3211 {
3212     taskExecutor_->PostTask(
3213         [weak = AceType::WeakClaim(this), pageId] {
3214             auto delegate = weak.Upgrade();
3215             if (delegate) {
3216                 delegate->destroyPage_(pageId);
3217                 delegate->RecyclePageId(pageId);
3218             }
3219         },
3220         TaskExecutor::TaskType::JS, "ArkUIPageDestroy");
3221 }
3222 
GetRunningPageId() const3223 int32_t FrontendDelegateDeclarative::GetRunningPageId() const
3224 {
3225     std::lock_guard<std::mutex> lock(mutex_);
3226     if (pageRouteStack_.empty()) {
3227         return INVALID_PAGE_ID;
3228     }
3229     return pageRouteStack_.back().pageId;
3230 }
3231 
GetRunningPageUrl() const3232 std::string FrontendDelegateDeclarative::GetRunningPageUrl() const
3233 {
3234     std::lock_guard<std::mutex> lock(mutex_);
3235     if (pageRouteStack_.empty()) {
3236         return std::string();
3237     }
3238     const auto& pageUrl = pageRouteStack_.back().url;
3239     auto pos = pageUrl.rfind(".js");
3240     if (pos == pageUrl.length() - 3) {
3241         return pageUrl.substr(0, pos);
3242     }
3243     return pageUrl;
3244 }
3245 
GetPageIdByUrl(const std::string & url,bool & isRestore)3246 int32_t FrontendDelegateDeclarative::GetPageIdByUrl(const std::string& url, bool& isRestore)
3247 {
3248     std::lock_guard<std::mutex> lock(mutex_);
3249     auto pageIter = std::find_if(std::rbegin(pageRouteStack_), std::rend(pageRouteStack_),
3250         [&url](const PageInfo& pageRoute) { return url == pageRoute.url; });
3251     if (pageIter != std::rend(pageRouteStack_)) {
3252         isRestore = pageIter->isRestore;
3253         return pageIter->pageId;
3254     }
3255     return INVALID_PAGE_ID;
3256 }
3257 
GetPage(int32_t pageId) const3258 RefPtr<JsAcePage> FrontendDelegateDeclarative::GetPage(int32_t pageId) const
3259 {
3260     std::lock_guard<std::mutex> lock(mutex_);
3261     auto itPage = pageMap_.find(pageId);
3262     if (itPage == pageMap_.end()) {
3263         LOGE("the page is not in the map");
3264         return nullptr;
3265     }
3266     return itPage->second;
3267 }
3268 
RegisterFont(const std::string & familyName,const std::string & familySrc,const std::string & bundleName,const std::string & moduleName)3269 void FrontendDelegateDeclarative::RegisterFont(const std::string& familyName, const std::string& familySrc,
3270     const std::string& bundleName, const std::string& moduleName)
3271 {
3272     pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc, bundleName, moduleName);
3273 }
3274 
GetSystemFontList(std::vector<std::string> & fontList)3275 void FrontendDelegateDeclarative::GetSystemFontList(std::vector<std::string>& fontList)
3276 {
3277     pipelineContextHolder_.Get()->GetSystemFontList(fontList);
3278 }
3279 
GetUIFontConfig(FontConfigJsonInfo & fontConfigJsonInfo)3280 void FrontendDelegateDeclarative::GetUIFontConfig(FontConfigJsonInfo& fontConfigJsonInfo)
3281 {
3282     pipelineContextHolder_.Get()->GetUIFontConfig(fontConfigJsonInfo);
3283 }
3284 
GetSystemFont(const std::string & fontName,FontInfo & fontInfo)3285 bool FrontendDelegateDeclarative::GetSystemFont(const std::string& fontName, FontInfo& fontInfo)
3286 {
3287     return pipelineContextHolder_.Get()->GetSystemFont(fontName, fontInfo);
3288 }
3289 
HandleImage(const std::string & src,std::function<void (bool,int32_t,int32_t)> && callback)3290 void FrontendDelegateDeclarative::HandleImage(
3291     const std::string& src, std::function<void(bool, int32_t, int32_t)>&& callback)
3292 {
3293     LOGW("Not implement in declarative frontend.");
3294 }
3295 
PushJsCallbackToRenderNode(NodeId id,double ratio,std::function<void (bool,double)> && callback)3296 void FrontendDelegateDeclarative::PushJsCallbackToRenderNode(
3297     NodeId id, double ratio, std::function<void(bool, double)>&& callback)
3298 {
3299     LOGW("Not implement in declarative frontend.");
3300 }
3301 
RequestAnimationFrame(const std::string & callbackId)3302 void FrontendDelegateDeclarative::RequestAnimationFrame(const std::string& callbackId)
3303 {
3304     CancelableCallback<void()> cancelableTask;
3305     cancelableTask.Reset([callbackId, call = requestAnimationCallback_, weak = AceType::WeakClaim(this)] {
3306         auto delegate = weak.Upgrade();
3307         if (delegate && call) {
3308             call(callbackId, delegate->GetSystemRealTime());
3309         }
3310     });
3311     animationFrameTaskMap_.try_emplace(callbackId, cancelableTask);
3312     animationFrameTaskIds_.emplace(callbackId);
3313 }
3314 
GetSystemRealTime()3315 uint64_t FrontendDelegateDeclarative::GetSystemRealTime()
3316 {
3317     struct timespec ts;
3318     clock_gettime(CLOCK_REALTIME, &ts);
3319     return ts.tv_sec * TO_MILLI + ts.tv_nsec / NANO_TO_MILLI;
3320 }
3321 
CancelAnimationFrame(const std::string & callbackId)3322 void FrontendDelegateDeclarative::CancelAnimationFrame(const std::string& callbackId)
3323 {
3324     auto animationTaskIter = animationFrameTaskMap_.find(callbackId);
3325     if (animationTaskIter != animationFrameTaskMap_.end()) {
3326         animationTaskIter->second.Cancel();
3327         animationFrameTaskMap_.erase(animationTaskIter);
3328     } else {
3329         LOGW("cancelAnimationFrame callbackId not found");
3330     }
3331 }
3332 
FlushAnimationTasks()3333 void FrontendDelegateDeclarative::FlushAnimationTasks()
3334 {
3335     while (!animationFrameTaskIds_.empty()) {
3336         const auto& callbackId = animationFrameTaskIds_.front();
3337         if (!callbackId.empty()) {
3338             auto taskIter = animationFrameTaskMap_.find(callbackId);
3339             if (taskIter != animationFrameTaskMap_.end()) {
3340                 taskExecutor_->PostTask(taskIter->second, TaskExecutor::TaskType::JS, "ArkUIFlushAnimationTask");
3341             }
3342         }
3343         animationFrameTaskIds_.pop();
3344     }
3345 }
3346 
GetAnimationJsTask()3347 SingleTaskExecutor FrontendDelegateDeclarative::GetAnimationJsTask()
3348 {
3349     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::JS);
3350 }
3351 
GetUiTask()3352 SingleTaskExecutor FrontendDelegateDeclarative::GetUiTask()
3353 {
3354     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::UI);
3355 }
3356 
AttachPipelineContext(const RefPtr<PipelineBase> & context)3357 void FrontendDelegateDeclarative::AttachPipelineContext(const RefPtr<PipelineBase>& context)
3358 {
3359     if (!context) {
3360         return;
3361     }
3362     context->SetOnPageShow([weak = AceType::WeakClaim(this)] {
3363         auto delegate = weak.Upgrade();
3364         if (delegate) {
3365             delegate->OnPageShow();
3366         }
3367     });
3368     context->SetAnimationCallback([weak = AceType::WeakClaim(this)] {
3369         auto delegate = weak.Upgrade();
3370         if (delegate) {
3371             delegate->FlushAnimationTasks();
3372         }
3373     });
3374     pipelineContextHolder_.Attach(context);
3375     jsAccessibilityManager_->SetPipelineContext(context);
3376     jsAccessibilityManager_->InitializeCallback();
3377 }
3378 
AttachSubPipelineContext(const RefPtr<PipelineBase> & context)3379 void FrontendDelegateDeclarative::AttachSubPipelineContext(const RefPtr<PipelineBase>& context)
3380 {
3381     if (!context) {
3382         return;
3383     }
3384     jsAccessibilityManager_->AddSubPipelineContext(context);
3385     jsAccessibilityManager_->RegisterSubWindowInteractionOperation(context->GetWindowId());
3386 }
3387 
GetPipelineContext()3388 RefPtr<PipelineBase> FrontendDelegateDeclarative::GetPipelineContext()
3389 {
3390     return pipelineContextHolder_.Get();
3391 }
3392 
RestoreRouterStack(const std::string & contentInfo,ContentInfoType type)3393 std::pair<RouterRecoverRecord, UIContentErrorCode> FrontendDelegateDeclarative::RestoreRouterStack(
3394     const std::string& contentInfo, ContentInfoType type)
3395 {
3396     LOGI("FrontendDelegateDeclarative::RestoreRouterStack: contentInfo = %{public}s", contentInfo.c_str());
3397     auto jsonContentInfo = JsonUtil::ParseJsonString(contentInfo);
3398     if (!jsonContentInfo->IsValid() || !jsonContentInfo->IsObject()) {
3399         LOGW("restore contentInfo is invalid");
3400         return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
3401     }
3402     if (type == ContentInfoType::CONTINUATION || type == ContentInfoType::APP_RECOVERY) {
3403         // restore node info
3404         auto jsonNodeInfo = jsonContentInfo->GetValue("nodeInfo");
3405         auto pipelineContext = pipelineContextHolder_.Get();
3406         CHECK_NULL_RETURN(pipelineContext,
3407             std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER));
3408         pipelineContext->RestoreNodeInfo(std::move(jsonNodeInfo));
3409     }
3410 
3411     // restore stack info
3412     auto routerStack = jsonContentInfo->GetValue("stackInfo");
3413     if (!Container::IsCurrentUseNewPipeline()) {
3414         std::lock_guard<std::mutex> lock(mutex_);
3415         if (!routerStack->IsValid() || !routerStack->IsArray()) {
3416             LOGW("restore router stack is invalid");
3417             return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
3418         }
3419         int32_t stackSize = routerStack->GetArraySize();
3420         if (stackSize < 1) {
3421             LOGW("restore stack size: %{public}d is invalid", stackSize);
3422             return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
3423         }
3424         for (int32_t index = 0; index < stackSize - 1; ++index) {
3425             std::string url = routerStack->GetArrayItem(index)->ToString();
3426             // remove 2 useless character, as "XXX" to XXX
3427             PageInfo pageInfo;
3428             pageInfo.pageId = GenerateNextPageId();
3429             pageInfo.url = url.substr(1, url.size() - USELESS_CHARACTER_SIZE);
3430             pageInfo.isRestore = true;
3431             pageRouteStack_.emplace_back(pageInfo);
3432         }
3433         std::string startUrl = routerStack->GetArrayItem(stackSize - 1)->ToString();
3434         // remove 5 useless character, as "XXX.js" to XXX
3435         return std::make_pair(RouterRecoverRecord(startUrl.substr(1, startUrl.size() - 5), "", false),
3436             UIContentErrorCode::NO_ERRORS);
3437     }
3438 
3439     CHECK_NULL_RETURN(pageRouterManager_,
3440         std::make_pair(RouterRecoverRecord(), UIContentErrorCode::NULL_PAGE_ROUTER));
3441     if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY) {
3442         auto namedRouterInfo = jsonContentInfo->GetValue("namedRouterInfo");
3443         if (namedRouterInfo && namedRouterInfo->IsValid()) {
3444             if (!namedRouterInfo->IsArray()) {
3445                 LOGD("restore named router info is invalid");
3446                 return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
3447             }
3448             pageRouterManager_->RestoreNamedRouterInfo(std::move(namedRouterInfo));
3449         }
3450         auto fullPathInfo = jsonContentInfo->GetValue("fullPathInfo");
3451         if (fullPathInfo && fullPathInfo->IsValid()) {
3452             if (!fullPathInfo->IsArray()) {
3453                 LOGD("restore full path info is invalid");
3454                 return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
3455             }
3456             pageRouterManager_->RestoreFullPathInfo(std::move(fullPathInfo));
3457         }
3458     }
3459     // restore navigation info
3460     auto pipelineContextNG = AceType::DynamicCast<NG::PipelineContext>(pipelineContextHolder_.Get());
3461     if (pipelineContextNG && pipelineContextNG->GetNavigationManager()) {
3462         auto navigationRecoveryInfo = jsonContentInfo->GetValue("navigationInfo");
3463         pipelineContextNG->GetNavigationManager()->StorageNavigationRecoveryInfo(std::move(navigationRecoveryInfo));
3464     }
3465     return pageRouterManager_->RestoreRouterStack(std::move(routerStack), type);
3466 }
3467 
GetContentInfo(ContentInfoType type)3468 std::string FrontendDelegateDeclarative::GetContentInfo(ContentInfoType type)
3469 {
3470     auto jsonContentInfo = JsonUtil::Create(true);
3471 
3472     if (!Container::IsCurrentUseNewPipeline()) {
3473         std::lock_guard<std::mutex> lock(mutex_);
3474         auto jsonRouterStack = JsonUtil::CreateArray(true);
3475         for (size_t index = 0; index < pageRouteStack_.size(); ++index) {
3476             jsonRouterStack->Put("", pageRouteStack_[index].url.c_str());
3477         }
3478         jsonContentInfo->Put("stackInfo", jsonRouterStack);
3479     } else {
3480         CHECK_NULL_RETURN(pageRouterManager_, "");
3481         jsonContentInfo->Put("stackInfo", pageRouterManager_->GetStackInfo(type));
3482         if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY) {
3483             auto namedRouterInfo = pageRouterManager_->GetNamedRouterInfo();
3484             if (namedRouterInfo) {
3485                 jsonContentInfo->Put("namedRouterInfo", std::move(namedRouterInfo));
3486             }
3487             auto fullPathInfo = pageRouterManager_->GetFullPathInfo();
3488             if (fullPathInfo) {
3489                 jsonContentInfo->Put("fullPathInfo", std::move(fullPathInfo));
3490             }
3491             // add navigation stack info
3492             auto navigationRecoveryInfo = GetNavigationJsonInfo();
3493             if (navigationRecoveryInfo) {
3494                 jsonContentInfo->Put("navigationInfo", navigationRecoveryInfo);
3495             }
3496         }
3497     }
3498 
3499     if (type == ContentInfoType::CONTINUATION || type == ContentInfoType::APP_RECOVERY) {
3500         auto pipelineContext = pipelineContextHolder_.Get();
3501         CHECK_NULL_RETURN(pipelineContext, jsonContentInfo->ToString());
3502         jsonContentInfo->Put("nodeInfo", pipelineContext->GetStoredNodeInfo());
3503     }
3504 
3505     return jsonContentInfo->ToString();
3506 }
3507 
GetSnapshot(const std::string & componentId,NG::ComponentSnapshot::JsCallback && callback,const NG::SnapshotOptions & options)3508 void FrontendDelegateDeclarative::GetSnapshot(
3509     const std::string& componentId, NG::ComponentSnapshot::JsCallback&& callback, const NG::SnapshotOptions& options)
3510 {
3511 #ifdef ENABLE_ROSEN_BACKEND
3512     NG::ComponentSnapshot::Get(componentId, std::move(callback), options);
3513 #endif
3514 }
3515 
GetSyncSnapshot(RefPtr<NG::FrameNode> & node,const NG::SnapshotOptions & options)3516 std::pair<int32_t, std::shared_ptr<Media::PixelMap>> FrontendDelegateDeclarative::GetSyncSnapshot(
3517     RefPtr<NG::FrameNode>& node, const NG::SnapshotOptions& options)
3518 {
3519 #ifdef ENABLE_ROSEN_BACKEND
3520     return NG::ComponentSnapshot::GetSync(node, options);
3521 #endif
3522     return { ERROR_CODE_INTERNAL_ERROR, nullptr };
3523 }
3524 
GetSyncSnapshot(const std::string & componentId,const NG::SnapshotOptions & options)3525 std::pair<int32_t, std::shared_ptr<Media::PixelMap>> FrontendDelegateDeclarative::GetSyncSnapshot(
3526     const std::string& componentId, const NG::SnapshotOptions& options)
3527 {
3528 #ifdef ENABLE_ROSEN_BACKEND
3529     return NG::ComponentSnapshot::GetSync(componentId, options);
3530 #endif
3531     return {ERROR_CODE_INTERNAL_ERROR, nullptr};
3532 }
3533 
GetSnapshotByUniqueId(int32_t uniqueId,std::function<void (std::shared_ptr<Media::PixelMap>,int32_t,std::function<void ()>)> && callback,const NG::SnapshotOptions & options)3534 void FrontendDelegateDeclarative::GetSnapshotByUniqueId(int32_t uniqueId,
3535     std::function<void(std::shared_ptr<Media::PixelMap>, int32_t, std::function<void()>)>&& callback,
3536     const NG::SnapshotOptions& options)
3537 {
3538 #ifdef ENABLE_ROSEN_BACKEND
3539     NG::ComponentSnapshot::GetByUniqueId(uniqueId, std::move(callback), options);
3540 #endif
3541 }
3542 
GetSyncSnapshotByUniqueId(int32_t uniqueId,const NG::SnapshotOptions & options)3543 std::pair<int32_t, std::shared_ptr<Media::PixelMap>> FrontendDelegateDeclarative::GetSyncSnapshotByUniqueId(
3544     int32_t uniqueId, const NG::SnapshotOptions& options)
3545 {
3546 #ifdef ENABLE_ROSEN_BACKEND
3547     return NG::ComponentSnapshot::GetSyncByUniqueId(uniqueId, options);
3548 #endif
3549     return {ERROR_CODE_INTERNAL_ERROR, nullptr};
3550 }
3551 
CreateSnapshot(std::function<void ()> && customBuilder,NG::ComponentSnapshot::JsCallback && callback,bool enableInspector,const NG::SnapshotParam & param)3552 void FrontendDelegateDeclarative::CreateSnapshot(
3553     std::function<void()>&& customBuilder, NG::ComponentSnapshot::JsCallback&& callback, bool enableInspector,
3554     const NG::SnapshotParam& param)
3555 {
3556 #ifdef ENABLE_ROSEN_BACKEND
3557     ViewStackModel::GetInstance()->NewScope();
3558     CHECK_NULL_VOID(customBuilder);
3559     customBuilder();
3560     auto customNode = ViewStackModel::GetInstance()->Finish();
3561 
3562     NG::ComponentSnapshot::Create(customNode, std::move(callback), enableInspector, param);
3563 #endif
3564 }
3565 
CreateSnapshotFromComponent(const RefPtr<NG::UINode> & nodeWk,NG::ComponentSnapshot::JsCallback && callback,bool enableInspector,const NG::SnapshotParam & param)3566 void FrontendDelegateDeclarative::CreateSnapshotFromComponent(const RefPtr<NG::UINode>& nodeWk,
3567     NG::ComponentSnapshot::JsCallback&& callback, bool enableInspector, const NG::SnapshotParam& param)
3568 {
3569 #ifdef ENABLE_ROSEN_BACKEND
3570     ViewStackModel::GetInstance()->NewScope();
3571     NG::ComponentSnapshot::Create(nodeWk, std::move(callback), enableInspector, param);
3572 #endif
3573 }
3574 
AddFrameNodeToOverlay(const RefPtr<NG::FrameNode> & node,std::optional<int32_t> index)3575 void FrontendDelegateDeclarative::AddFrameNodeToOverlay(const RefPtr<NG::FrameNode>& node, std::optional<int32_t> index)
3576 {
3577     auto task = [node, index, containerId = Container::CurrentId()](const RefPtr<NG::OverlayManager>& overlayManager) {
3578         CHECK_NULL_VOID(overlayManager);
3579         ContainerScope scope(containerId);
3580         overlayManager->AddFrameNodeToOverlay(node, index);
3581     };
3582     MainWindowOverlay(std::move(task), "ArkUIOverlayAddFrameNode", nullptr);
3583 }
3584 
AddFrameNodeWithOrder(const RefPtr<NG::FrameNode> & node,std::optional<double> levelOrder)3585 void FrontendDelegateDeclarative::AddFrameNodeWithOrder(const RefPtr<NG::FrameNode>& node,
3586     std::optional<double> levelOrder)
3587 {
3588     CHECK_NULL_VOID(node);
3589     auto pipelineContext = node->GetContext();
3590     CHECK_NULL_VOID(pipelineContext);
3591     auto overlayManager = pipelineContext->GetOverlayManager();
3592     CHECK_NULL_VOID(overlayManager);
3593     overlayManager->AddFrameNodeWithOrder(node, levelOrder);
3594 }
3595 
RemoveFrameNodeOnOverlay(const RefPtr<NG::FrameNode> & node)3596 void FrontendDelegateDeclarative::RemoveFrameNodeOnOverlay(const RefPtr<NG::FrameNode>& node)
3597 {
3598     auto task = [node, containerId = Container::CurrentId()](const RefPtr<NG::OverlayManager>& overlayManager) {
3599         CHECK_NULL_VOID(overlayManager);
3600         ContainerScope scope(containerId);
3601         overlayManager->RemoveFrameNodeOnOverlay(node);
3602     };
3603     MainWindowOverlay(std::move(task), "ArkUIOverlayRemoveFrameNode", nullptr);
3604 }
3605 
ShowNodeOnOverlay(const RefPtr<NG::FrameNode> & node)3606 void FrontendDelegateDeclarative::ShowNodeOnOverlay(const RefPtr<NG::FrameNode>& node)
3607 {
3608     auto task = [node, containerId = Container::CurrentId()](const RefPtr<NG::OverlayManager>& overlayManager) {
3609         CHECK_NULL_VOID(overlayManager);
3610         ContainerScope scope(containerId);
3611         overlayManager->ShowNodeOnOverlay(node);
3612     };
3613     MainWindowOverlay(std::move(task), "ArkUIOverlayShowNode", nullptr);
3614 }
3615 
HideNodeOnOverlay(const RefPtr<NG::FrameNode> & node)3616 void FrontendDelegateDeclarative::HideNodeOnOverlay(const RefPtr<NG::FrameNode>& node)
3617 {
3618     auto task = [node, containerId = Container::CurrentId()](const RefPtr<NG::OverlayManager>& overlayManager) {
3619         CHECK_NULL_VOID(overlayManager);
3620         ContainerScope scope(containerId);
3621         overlayManager->HideNodeOnOverlay(node);
3622     };
3623     MainWindowOverlay(std::move(task), "ArkUIOverlayHideNode", nullptr);
3624 }
3625 
ShowAllNodesOnOverlay()3626 void FrontendDelegateDeclarative::ShowAllNodesOnOverlay()
3627 {
3628     auto task = [containerId = Container::CurrentId()](const RefPtr<NG::OverlayManager>& overlayManager) {
3629         CHECK_NULL_VOID(overlayManager);
3630         ContainerScope scope(containerId);
3631         overlayManager->ShowAllNodesOnOverlay();
3632     };
3633     MainWindowOverlay(std::move(task), "ArkUIOverlayShowAllNodes", nullptr);
3634 }
3635 
HideAllNodesOnOverlay()3636 void FrontendDelegateDeclarative::HideAllNodesOnOverlay()
3637 {
3638     auto task = [containerId = Container::CurrentId()](const RefPtr<NG::OverlayManager>& overlayManager) {
3639         CHECK_NULL_VOID(overlayManager);
3640         ContainerScope scope(containerId);
3641         overlayManager->HideAllNodesOnOverlay();
3642     };
3643     MainWindowOverlay(std::move(task), "ArkUIOverlayHideAllNodes", nullptr);
3644 }
3645 
GetTransitionEffect(void * value)3646 RefPtr<NG::ChainedTransitionEffect> FrontendDelegateDeclarative::GetTransitionEffect(void* value)
3647 {
3648     napi_value napiVal = reinterpret_cast<napi_value>(value);
3649     JSRef<JSVal> transitionVal = JsConverter::ConvertNapiValueToJsVal(napiVal);
3650     if (transitionVal.IsEmpty() || !transitionVal->IsObject()) {
3651         LOGE("Convert TransitionEffect from napi value to JSVal failed.");
3652         return nullptr;
3653     }
3654     JSRef<JSObject> transitionObj = JSRef<JSObject>::Cast(transitionVal);
3655 
3656     auto engine = EngineHelper::GetCurrentEngine();
3657     CHECK_NULL_RETURN(engine, nullptr);
3658     NativeEngine* nativeEngine = engine->GetNativeEngine();
3659     auto arkNativeEngine = static_cast<ArkNativeEngine*>(nativeEngine);
3660     CHECK_NULL_RETURN(arkNativeEngine, nullptr);
3661     auto vm = const_cast<EcmaVM*>(arkNativeEngine->GetEcmaVm());
3662     CHECK_NULL_RETURN(vm, nullptr);
3663     JsiExecutionContext context = { vm };
3664 
3665     return JSViewAbstract::ParseNapiChainedTransition(transitionObj, context);
3666 }
3667 
GetNavigationJsonInfo()3668 std::unique_ptr<JsonValue> FrontendDelegateDeclarative::GetNavigationJsonInfo()
3669 {
3670     auto pipelineContextNG = AceType::DynamicCast<NG::PipelineContext>(pipelineContextHolder_.Get());
3671     CHECK_NULL_RETURN(pipelineContextNG, nullptr);
3672     auto navigationManager = pipelineContextNG->GetNavigationManager();
3673     CHECK_NULL_RETURN(navigationManager, nullptr);
3674     return navigationManager->GetNavigationJsonInfo();
3675 }
SetOverlayManagerOptions(const NG::OverlayManagerInfo & overlayInfo)3676 bool FrontendDelegateDeclarative::SetOverlayManagerOptions(const NG::OverlayManagerInfo& overlayInfo)
3677 {
3678     auto context = NG::PipelineContext::GetCurrentContext();
3679     CHECK_NULL_RETURN(context, false);
3680     auto overlayManager = context->GetOverlayManager();
3681     CHECK_NULL_RETURN(overlayManager, false);
3682     return overlayManager->SetOverlayManagerOptions(overlayInfo);
3683 };
GetOverlayManagerOptions()3684 std::optional<NG::OverlayManagerInfo> FrontendDelegateDeclarative::GetOverlayManagerOptions()
3685 {
3686     auto context = NG::PipelineContext::GetCurrentContext();
3687     CHECK_NULL_RETURN(context, std::nullopt);
3688     auto overlayManager = context->GetOverlayManager();
3689     CHECK_NULL_RETURN(overlayManager, std::nullopt);
3690     return overlayManager->GetOverlayManagerOptions();
3691 };
3692 
GetPagePathByUrl(const std::string & url) const3693 std::string FrontendDelegateDeclarative::GetPagePathByUrl(const std::string& url) const
3694 {
3695     if (!Container::IsCurrentUseNewPipeline()) {
3696         return "";
3697     }
3698     CHECK_NULL_RETURN(pageRouterManager_, "");
3699     auto currentId = GetEffectiveContainerId();
3700     if (!currentId.has_value()) {
3701         return "";
3702     }
3703     ContainerScope scope(currentId.value());
3704     std::string name;
3705     std::string path;
3706     pageRouterManager_->GetPageNameAndPath(url, name, path);
3707     return path + name;
3708 }
3709 } // namespace OHOS::Ace::Framework
3710