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