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