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