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