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