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