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