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