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