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