• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/declarative_frontend/frontend_delegate_declarative.h"
17 
18 #include <atomic>
19 #include <regex>
20 #include <string>
21 
22 #include "base/i18n/localization.h"
23 #include "base/log/ace_trace.h"
24 #include "base/log/event_report.h"
25 #include "base/resource/ace_res_config.h"
26 #include "base/thread/background_task_executor.h"
27 #include "base/utils/utils.h"
28 #include "core/common/ace_application_info.h"
29 #include "core/common/container.h"
30 #include "core/common/platform_bridge.h"
31 #include "core/common/thread_checker.h"
32 #include "core/components/dialog/dialog_component.h"
33 #include "core/components/toast/toast_component.h"
34 #include "frameworks/bridge/common/manifest/manifest_parser.h"
35 #include "frameworks/bridge/common/utils/utils.h"
36 #include "frameworks/bridge/js_frontend/js_ace_page.h"
37 
38 namespace OHOS::Ace::Framework {
39 namespace {
40 
41 constexpr int32_t INVALID_PAGE_ID = -1;
42 constexpr int32_t MAX_ROUTER_STACK = 32;
43 constexpr int32_t TOAST_TIME_MAX = 10000;    // ms
44 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
45 constexpr int32_t MAX_PAGE_ID_SIZE = sizeof(uint64_t) * 8;
46 constexpr int32_t NANO_TO_MILLI = 1000000; // nanosecond to millisecond
47 constexpr int32_t TO_MILLI = 1000;         // second to millisecond
48 constexpr int32_t CALLBACK_ERRORCODE_SUCCESS = 0;
49 constexpr int32_t CALLBACK_ERRORCODE_CANCEL = 1;
50 constexpr int32_t CALLBACK_ERRORCODE_COMPLETE = 2;
51 constexpr int32_t CALLBACK_DATACODE_ZERO = 0;
52 
53 const char MANIFEST_JSON[] = "manifest.json";
54 const char PAGES_JSON[] = "main_pages.json";
55 const char FILE_TYPE_JSON[] = ".json";
56 const char I18N_FOLDER[] = "i18n/";
57 const char RESOURCES_FOLDER[] = "resources/";
58 const char STYLES_FOLDER[] = "styles/";
59 const char I18N_FILE_SUFFIX[] = "/properties/string.json";
60 
61 } // namespace
62 
GenerateNextPageId()63 int32_t FrontendDelegateDeclarative::GenerateNextPageId()
64 {
65     for (int32_t idx = 0; idx < MAX_PAGE_ID_SIZE; ++idx) {
66         uint64_t bitMask = (1ULL << idx);
67         if ((bitMask & pageIdPool_.fetch_or(bitMask, std::memory_order_relaxed)) == 0) {
68             return idx;
69         }
70     }
71     return INVALID_PAGE_ID;
72 }
73 
RecyclePageId(int32_t pageId)74 void FrontendDelegateDeclarative::RecyclePageId(int32_t pageId)
75 {
76     if (pageId < 0 || pageId >= MAX_PAGE_ID_SIZE) {
77         return;
78     }
79     uint64_t bitMask = (1ULL << pageId);
80     pageIdPool_.fetch_and(~bitMask, std::memory_order_relaxed);
81 }
82 
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 OnActiveCallBack & onActiveCallBack,const OnInactiveCallBack & onInactiveCallBack,const OnMemoryLevelCallBack & onMemoryLevelCallBack,const OnStartContinuationCallBack & onStartContinuationCallBack,const OnCompleteContinuationCallBack & onCompleteContinuationCallBack,const OnRemoteTerminatedCallBack & onRemoteTerminatedCallBack,const OnSaveDataCallBack & onSaveDataCallBack,const OnRestoreDataCallBack & onRestoreDataCallBack,const ExternalEventCallback & externalEventCallback)83 FrontendDelegateDeclarative::FrontendDelegateDeclarative(const RefPtr<TaskExecutor>& taskExecutor,
84     const LoadJsCallback& loadCallback, const JsMessageDispatcherSetterCallback& transferCallback,
85     const EventCallback& asyncEventCallback, const EventCallback& syncEventCallback,
86     const UpdatePageCallback& updatePageCallback, const ResetStagingPageCallback& resetLoadingPageCallback,
87     const DestroyPageCallback& destroyPageCallback, const DestroyApplicationCallback& destroyApplicationCallback,
88     const UpdateApplicationStateCallback& updateApplicationStateCallback,
89     const TimerCallback& timerCallback, const MediaQueryCallback& mediaQueryCallback,
90     const RequestAnimationCallback& requestAnimationCallback, const JsCallback& jsCallback,
91     const OnWindowDisplayModeChangedCallBack& onWindowDisplayModeChangedCallBack,
92     const OnConfigurationUpdatedCallBack& onConfigurationUpdatedCallBack,
93     const OnSaveAbilityStateCallBack& onSaveAbilityStateCallBack,
94     const OnRestoreAbilityStateCallBack& onRestoreAbilityStateCallBack,
95     const OnNewWantCallBack& onNewWantCallBack,
96     const OnActiveCallBack& onActiveCallBack,
97     const OnInactiveCallBack& onInactiveCallBack, const OnMemoryLevelCallBack& onMemoryLevelCallBack,
98     const OnStartContinuationCallBack& onStartContinuationCallBack,
99     const OnCompleteContinuationCallBack& onCompleteContinuationCallBack,
100     const OnRemoteTerminatedCallBack& onRemoteTerminatedCallBack,
101     const OnSaveDataCallBack& onSaveDataCallBack,
102     const OnRestoreDataCallBack& onRestoreDataCallBack,
103     const ExternalEventCallback& externalEventCallback)
104     : loadJs_(loadCallback), externalEvent_(externalEventCallback),
105       dispatcherCallback_(transferCallback), asyncEvent_(asyncEventCallback),
106       syncEvent_(syncEventCallback), updatePage_(updatePageCallback), resetStagingPage_(resetLoadingPageCallback),
107       destroyPage_(destroyPageCallback), destroyApplication_(destroyApplicationCallback),
108       updateApplicationState_(updateApplicationStateCallback), timer_(timerCallback),
109       mediaQueryCallback_(mediaQueryCallback), requestAnimationCallback_(requestAnimationCallback),
110       jsCallback_(jsCallback), onWindowDisplayModeChanged_(onWindowDisplayModeChangedCallBack),
111       onConfigurationUpdated_(onConfigurationUpdatedCallBack),
112       onSaveAbilityState_(onSaveAbilityStateCallBack), onRestoreAbilityState_(onRestoreAbilityStateCallBack),
113       onNewWant_(onNewWantCallBack), onActive_(onActiveCallBack),
114       onInactive_(onInactiveCallBack), onMemoryLevel_(onMemoryLevelCallBack),
115       onStartContinuationCallBack_(onStartContinuationCallBack),
116       onCompleteContinuationCallBack_(onCompleteContinuationCallBack),
117       onRemoteTerminatedCallBack_(onRemoteTerminatedCallBack),
118       onSaveDataCallBack_(onSaveDataCallBack),
119       onRestoreDataCallBack_(onRestoreDataCallBack),
120       manifestParser_(AceType::MakeRefPtr<ManifestParser>()),
121       jsAccessibilityManager_(AccessibilityNodeManager::Create()),
122       mediaQueryInfo_(AceType::MakeRefPtr<MediaQueryInfo>()), taskExecutor_(taskExecutor)
123 {
124     LOGD("FrontendDelegateDeclarative create");
125 }
126 
~FrontendDelegateDeclarative()127 FrontendDelegateDeclarative::~FrontendDelegateDeclarative()
128 {
129     CHECK_RUN_ON(JS);
130     LOG_DESTROY();
131 }
132 
GetMinPlatformVersion()133 int32_t FrontendDelegateDeclarative::GetMinPlatformVersion()
134 {
135     return manifestParser_->GetMinPlatformVersion();
136 }
137 
RunPage(const std::string & url,const std::string & params,const std::string & profile)138 void FrontendDelegateDeclarative::RunPage(const std::string& url, const std::string& params, const std::string& profile)
139 {
140     ACE_SCOPED_TRACE("FrontendDelegateDeclarative::RunPage");
141 
142     LOGI("FrontendDelegateDeclarative RunPage url=%{public}s", url.c_str());
143     std::string jsonContent;
144     if (GetAssetContent(MANIFEST_JSON, jsonContent)) {
145         manifestParser_->Parse(jsonContent);
146         manifestParser_->Printer();
147     } else if (!profile.empty() && GetAssetContent(profile, jsonContent)) {
148         LOGI("Parse profile %{public}s", profile.c_str());
149         manifestParser_->Parse(jsonContent);
150     } else if (GetAssetContent(PAGES_JSON, jsonContent)) {
151         LOGI("Parse main_pages.json");
152         manifestParser_->Parse(jsonContent);
153     } else {
154         LOGE("RunPage parse manifest.json failed");
155         EventReport::SendPageRouterException(PageRouterExcepType::RUN_PAGE_ERR, url);
156     }
157     taskExecutor_->PostTask(
158         [weak = AceType::WeakClaim(this)]() {
159             auto delegate = weak.Upgrade();
160             if (delegate) {
161                 delegate->manifestParser_->GetAppInfo()->ParseI18nJsonInfo();
162             }
163         },
164         TaskExecutor::TaskType::JS);
165     if (!url.empty()) {
166         mainPagePath_ = manifestParser_->GetRouter()->GetPagePath(url);
167     } else {
168         mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
169     }
170     LoadPage(GenerateNextPageId(), PageTarget(mainPagePath_), true, params);
171 }
172 
ChangeLocale(const std::string & language,const std::string & countryOrRegion)173 void FrontendDelegateDeclarative::ChangeLocale(const std::string& language, const std::string& countryOrRegion)
174 {
175     LOGD("JSFrontend ChangeLocale");
176     taskExecutor_->PostTask(
177         [language, countryOrRegion]() { AceApplicationInfo::GetInstance().ChangeLocale(language, countryOrRegion); },
178         TaskExecutor::TaskType::PLATFORM);
179 }
180 
GetI18nData(std::unique_ptr<JsonValue> & json)181 void FrontendDelegateDeclarative::GetI18nData(std::unique_ptr<JsonValue>& json)
182 {
183     auto data = JsonUtil::CreateArray(true);
184     GetConfigurationCommon(I18N_FOLDER, data);
185     auto i18nData = JsonUtil::Create(true);
186     i18nData->Put("resources", data);
187     json->Put("i18n", i18nData);
188 }
189 
GetResourceConfiguration(std::unique_ptr<JsonValue> & json)190 void FrontendDelegateDeclarative::GetResourceConfiguration(std::unique_ptr<JsonValue>& json)
191 {
192     auto data = JsonUtil::CreateArray(true);
193     GetConfigurationCommon(RESOURCES_FOLDER, data);
194     json->Put("resourcesConfiguration", data);
195 }
196 
GetConfigurationCommon(const std::string & filePath,std::unique_ptr<JsonValue> & data)197 void FrontendDelegateDeclarative::GetConfigurationCommon(const std::string& filePath, std::unique_ptr<JsonValue>& data)
198 {
199     std::vector<std::string> files;
200     if (assetManager_) {
201         assetManager_->GetAssetList(filePath, files);
202     }
203 
204     std::vector<std::string> fileNameList;
205     for (const auto& file : files) {
206         if (EndWith(file, FILE_TYPE_JSON) && !StartWith(file, STYLES_FOLDER)) {
207             fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
208         }
209     }
210 
211     std::vector<std::string> priorityFileName;
212     if (filePath.compare(I18N_FOLDER) == 0) {
213         auto localeTag = AceApplicationInfo::GetInstance().GetLocaleTag();
214         priorityFileName = AceResConfig::GetLocaleFallback(localeTag, fileNameList);
215     } else {
216         priorityFileName = AceResConfig::GetResourceFallback(fileNameList);
217     }
218 
219     for (const auto& fileName : priorityFileName) {
220         auto fileFullPath = filePath + fileName + std::string(FILE_TYPE_JSON);
221         std::string content;
222         if (GetAssetContent(fileFullPath, content)) {
223             auto fileData = ParseFileData(content);
224             if (fileData == nullptr) {
225                 LOGW("parse %{private}s.json content failed", filePath.c_str());
226             } else {
227                 data->Put(fileData);
228             }
229         }
230     }
231 }
232 
LoadResourceConfiguration(std::map<std::string,std::string> & mediaResourceFileMap,std::unique_ptr<JsonValue> & currentResourceData)233 void FrontendDelegateDeclarative::LoadResourceConfiguration(std::map<std::string, std::string>& mediaResourceFileMap,
234     std::unique_ptr<JsonValue>& currentResourceData)
235 {
236     std::vector<std::string> files;
237     if (assetManager_) {
238         assetManager_->GetAssetList(RESOURCES_FOLDER, files);
239     }
240 
241     std::set<std::string> resourceFolderName;
242     for (const auto& file : files) {
243         if (file.find_first_of("/") != std::string::npos) {
244             resourceFolderName.insert(file.substr(0, file.find_first_of("/")));
245         }
246     }
247 
248     std::vector<std::string> sortedResourceFolderPath =
249         AceResConfig::GetDeclarativeResourceFallback(resourceFolderName);
250     for (const auto& folderName : sortedResourceFolderPath) {
251         auto fileFullPath = std::string(RESOURCES_FOLDER) + folderName + std::string(I18N_FILE_SUFFIX);
252         std::string content;
253         if (GetAssetContent(fileFullPath, content)) {
254             auto fileData = ParseFileData(content);
255             if (fileData == nullptr) {
256                 LOGW("parse %{private}s i18n content failed", fileFullPath.c_str());
257             } else {
258                 currentResourceData->Put(fileData);
259             }
260         }
261     }
262 
263     std::set<std::string> mediaFileName;
264     for (const auto& file : files) {
265         if (file.find_first_of("/") == std::string::npos) {
266             continue;
267         }
268         auto mediaPathName = file.substr(file.find_first_of("/"));
269         std::regex mediaPartten("^\\/media\\/\\w*(\\.jpg|\\.png|\\.gif|\\.svg|\\.webp|\\.bmp)$");
270         std::smatch result;
271         if (std::regex_match(mediaPathName, result, mediaPartten)) {
272             mediaFileName.insert(mediaPathName.substr(mediaPathName.find_first_of("/")));
273         }
274     }
275 
276     auto currentResTag = AceResConfig::GetCurrentDeviceResTag();
277     auto currentResolutionTag = currentResTag.substr(currentResTag.find_last_of("-") + 1);
278     for (auto folderName : sortedResourceFolderPath) {
279         for (auto fileName : mediaFileName) {
280             if (mediaResourceFileMap.find(fileName) != mediaResourceFileMap.end()) {
281                 continue;
282             }
283             auto fullFileName = folderName + fileName;
284             if (std::find(files.begin(), files.end(), fullFileName) != files.end()) {
285                 mediaResourceFileMap.emplace(fileName.substr(fileName.find_last_of("/") + 1),
286                     std::string(RESOURCES_FOLDER).append(fullFileName));
287             }
288         }
289         if (mediaResourceFileMap.size() == mediaFileName.size()) {
290             break;
291         }
292     }
293 }
294 
OnJSCallback(const std::string & callbackId,const std::string & data)295 void FrontendDelegateDeclarative::OnJSCallback(const std::string& callbackId, const std::string& data)
296 {
297     taskExecutor_->PostTask(
298         [weak = AceType::WeakClaim(this), callbackId, args = std::move(data)] {
299             auto delegate = weak.Upgrade();
300             if (delegate) {
301                 delegate->jsCallback_(callbackId, args);
302             }
303         },
304         TaskExecutor::TaskType::JS);
305 }
306 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher) const307 void FrontendDelegateDeclarative::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) const
308 {
309     LOGD("FrontendDelegateDeclarative SetJsMessageDispatcher");
310     taskExecutor_->PostTask([dispatcherCallback = dispatcherCallback_, dispatcher] { dispatcherCallback(dispatcher); },
311         TaskExecutor::TaskType::JS);
312 }
313 
TransferComponentResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data)314 void FrontendDelegateDeclarative::TransferComponentResponseData(int32_t callbackId, int32_t code,
315     std::vector<uint8_t>&& data)
316 {
317     LOGD("FrontendDelegateDeclarative TransferComponentResponseData");
318     auto pipelineContext = pipelineContextHolder_.Get();
319     WeakPtr<PipelineContext> contextWeak(pipelineContext);
320     taskExecutor_->PostTask(
321         [callbackId, data = std::move(data), contextWeak]() mutable {
322             auto context = contextWeak.Upgrade();
323             if (!context) {
324                 LOGE("context is null");
325             } else if (!context->GetMessageBridge()) {
326                 LOGE("messageBridge is null");
327             } else {
328                 context->GetMessageBridge()->HandleCallback(callbackId, std::move(data));
329             }
330         },
331         TaskExecutor::TaskType::UI);
332 }
333 
TransferJsResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const334 void FrontendDelegateDeclarative::TransferJsResponseData(
335     int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
336 {
337     LOGD("FrontendDelegateDeclarative TransferJsResponseData");
338     if (groupJsBridge_ && groupJsBridge_->ForwardToWorker(callbackId)) {
339         LOGD("FrontendDelegateDeclarative Forward to worker.");
340         groupJsBridge_->TriggerModuleJsCallback(callbackId, code, std::move(data));
341         return;
342     }
343 
344     taskExecutor_->PostTask(
345         [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
346             if (groupJsBridge) {
347                 groupJsBridge->TriggerModuleJsCallback(callbackId, code, std::move(data));
348             }
349         },
350         TaskExecutor::TaskType::JS);
351 }
352 
353 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const354 void FrontendDelegateDeclarative::TransferJsResponseDataPreview(
355     int32_t callbackId, int32_t code, ResponseData responseData) const
356 {
357     LOGI("FrontendDelegateDeclarative TransferJsResponseDataPreview");
358     taskExecutor_->PostTask(
359         [callbackId, code, responseData, groupJsBridge = groupJsBridge_]() mutable {
360             if (groupJsBridge) {
361                 groupJsBridge->TriggerModuleJsCallbackPreview(callbackId, code, responseData);
362             }
363         },
364         TaskExecutor::TaskType::JS);
365 }
366 #endif
367 
TransferJsPluginGetError(int32_t callbackId,int32_t errorCode,std::string && errorMessage) const368 void FrontendDelegateDeclarative::TransferJsPluginGetError(
369     int32_t callbackId, int32_t errorCode, std::string&& errorMessage) const
370 {
371     LOGD("FrontendDelegateDeclarative TransferJsPluginGetError");
372     taskExecutor_->PostTask(
373         [callbackId, errorCode, errorMessage = std::move(errorMessage), groupJsBridge = groupJsBridge_]() mutable {
374             if (groupJsBridge) {
375                 groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, errorCode, std::move(errorMessage));
376             }
377         },
378         TaskExecutor::TaskType::JS);
379 }
380 
TransferJsEventData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const381 void FrontendDelegateDeclarative::TransferJsEventData(int32_t callbackId, int32_t code,
382     std::vector<uint8_t>&& data) const
383 {
384     taskExecutor_->PostTask(
385         [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
386             if (groupJsBridge) {
387                 groupJsBridge->TriggerEventJsCallback(callbackId, code, std::move(data));
388             }
389         },
390         TaskExecutor::TaskType::JS);
391 }
392 
LoadPluginJsCode(std::string && jsCode) const393 void FrontendDelegateDeclarative::LoadPluginJsCode(std::string&& jsCode) const
394 {
395     LOGD("FrontendDelegateDeclarative LoadPluginJsCode");
396     taskExecutor_->PostTask(
397         [jsCode = std::move(jsCode), groupJsBridge = groupJsBridge_]() mutable {
398             if (groupJsBridge) {
399                 groupJsBridge->LoadPluginJsCode(std::move(jsCode));
400             }
401         },
402         TaskExecutor::TaskType::JS);
403 }
404 
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen) const405 void FrontendDelegateDeclarative::LoadPluginJsByteCode(
406     std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen) const
407 {
408     LOGD("FrontendDelegateDeclarative LoadPluginJsByteCode");
409     if (groupJsBridge_ == nullptr) {
410         LOGE("groupJsBridge_ is nullptr");
411         return;
412     }
413     taskExecutor_->PostTask(
414         [jsCode = std::move(jsCode), jsCodeLen = std::move(jsCodeLen), groupJsBridge = groupJsBridge_]() mutable {
415             groupJsBridge->LoadPluginJsByteCode(std::move(jsCode), std::move(jsCodeLen));
416         },
417         TaskExecutor::TaskType::JS);
418 }
419 
OnPageBackPress()420 bool FrontendDelegateDeclarative::OnPageBackPress()
421 {
422     auto result = false;
423     taskExecutor_->PostSyncTask(
424         [weak = AceType::WeakClaim(this), &result] {
425             auto delegate = weak.Upgrade();
426             if (!delegate) {
427                 return;
428             }
429             auto pageId = delegate->GetRunningPageId();
430             auto page = delegate->GetPage(pageId);
431             if (page) {
432                 result = page->FireDeclarativeOnBackPressCallback();
433             }
434         },
435         TaskExecutor::TaskType::JS);
436     return result;
437 }
438 
NotifyAppStorage(const WeakPtr<Framework::JsEngine> & jsEngineWeak,const std::string & key,const std::string & value)439 void FrontendDelegateDeclarative::NotifyAppStorage(const WeakPtr<Framework::JsEngine>& jsEngineWeak,
440     const std::string& key, const std::string& value)
441 {
442     taskExecutor_->PostTask(
443         [jsEngineWeak, key, value] {
444             auto jsEngine = jsEngineWeak.Upgrade();
445             if (!jsEngine) {
446                 return;
447             }
448             jsEngine->NotifyAppStorage(key, value);
449         },
450         TaskExecutor::TaskType::JS);
451 }
452 
OnSuspended()453 void FrontendDelegateDeclarative::OnSuspended()
454 {
455     FireAsyncEvent("_root", std::string("\"viewsuspended\",null,null"), std::string(""));
456 }
457 
OnBackGround()458 void FrontendDelegateDeclarative::OnBackGround()
459 {
460     taskExecutor_->PostTask(
461         [weak = AceType::WeakClaim(this)] {
462             auto delegate = weak.Upgrade();
463             if (!delegate) {
464                 return;
465             }
466             delegate->OnPageHide();
467         },
468         TaskExecutor::TaskType::JS);
469 }
470 
OnForground()471 void FrontendDelegateDeclarative::OnForground()
472 {
473     taskExecutor_->PostTask(
474         [weak = AceType::WeakClaim(this)] {
475             auto delegate = weak.Upgrade();
476             if (!delegate) {
477                 return;
478             }
479             delegate->OnPageShow();
480         },
481         TaskExecutor::TaskType::JS);
482 }
483 
OnConfigurationUpdated(const std::string & data)484 void FrontendDelegateDeclarative::OnConfigurationUpdated(const std::string& data)
485 {
486     taskExecutor_->PostSyncTask(
487         [onConfigurationUpdated = onConfigurationUpdated_, data] {
488             onConfigurationUpdated(data);
489         },
490         TaskExecutor::TaskType::JS);
491 }
492 
OnStartContinuation()493 bool FrontendDelegateDeclarative::OnStartContinuation()
494 {
495     bool ret = false;
496     taskExecutor_->PostSyncTask(
497         [weak = AceType::WeakClaim(this), &ret] {
498             auto delegate = weak.Upgrade();
499             if (delegate && delegate->onStartContinuationCallBack_) {
500                 ret = delegate->onStartContinuationCallBack_();
501             }
502         },
503         TaskExecutor::TaskType::JS);
504     return ret;
505 }
506 
OnCompleteContinuation(int32_t code)507 void FrontendDelegateDeclarative::OnCompleteContinuation(int32_t code)
508 {
509     taskExecutor_->PostSyncTask(
510         [weak = AceType::WeakClaim(this), code] {
511             auto delegate = weak.Upgrade();
512             if (delegate && delegate->onCompleteContinuationCallBack_) {
513                 delegate->onCompleteContinuationCallBack_(code);
514             }
515         },
516         TaskExecutor::TaskType::JS);
517 }
518 
OnRemoteTerminated()519 void FrontendDelegateDeclarative::OnRemoteTerminated()
520 {
521     taskExecutor_->PostSyncTask(
522         [weak = AceType::WeakClaim(this)] {
523             auto delegate = weak.Upgrade();
524             if (delegate && delegate->onRemoteTerminatedCallBack_) {
525                 delegate->onRemoteTerminatedCallBack_();
526             }
527         },
528         TaskExecutor::TaskType::JS);
529 }
530 
OnSaveData(std::string & data)531 void FrontendDelegateDeclarative::OnSaveData(std::string& data)
532 {
533     std::string savedData;
534     taskExecutor_->PostSyncTask(
535         [weak = AceType::WeakClaim(this), &savedData] {
536             auto delegate = weak.Upgrade();
537             if (delegate && delegate->onSaveDataCallBack_) {
538                 delegate->onSaveDataCallBack_(savedData);
539             }
540         },
541         TaskExecutor::TaskType::JS);
542     std::string pageUri = GetRunningPageUrl();
543     data = std::string("{\"url\":\"").append(pageUri).append("\",\"__remoteData\":").append(savedData).append("}");
544 }
545 
OnRestoreData(const std::string & data)546 bool FrontendDelegateDeclarative::OnRestoreData(const std::string& data)
547 {
548     bool ret = false;
549     taskExecutor_->PostSyncTask(
550         [weak = AceType::WeakClaim(this), &data, &ret] {
551             auto delegate = weak.Upgrade();
552             if (delegate && delegate->onRestoreDataCallBack_) {
553                 ret = delegate->onRestoreDataCallBack_(data);
554             }
555         },
556         TaskExecutor::TaskType::JS);
557     return ret;
558 }
559 
OnMemoryLevel(const int32_t level)560 void FrontendDelegateDeclarative::OnMemoryLevel(const int32_t level)
561 {
562     taskExecutor_->PostTask(
563         [onMemoryLevel = onMemoryLevel_, level]() {
564             if (onMemoryLevel) {
565                 onMemoryLevel(level);
566             }
567         },
568         TaskExecutor::TaskType::JS);
569 }
570 
GetPluginsUsed(std::string & data)571 void FrontendDelegateDeclarative::GetPluginsUsed(std::string& data)
572 {
573     if (!GetAssetContentImpl(assetManager_, "module_collection.txt", data)) {
574         LOGW("read failed, will load all the system plugin");
575         data = "All";
576     }
577 }
578 
OnActive()579 void FrontendDelegateDeclarative::OnActive()
580 {
581     taskExecutor_->PostTask(
582         [onActive = onActive_]() {
583             onActive();
584         },
585         TaskExecutor::TaskType::JS);
586 }
587 
OnInactive()588 void FrontendDelegateDeclarative::OnInactive()
589 {
590     taskExecutor_->PostTask(
591         [onInactive = onInactive_]() {
592             onInactive();
593         },
594         TaskExecutor::TaskType::JS);
595 }
596 
OnNewRequest(const std::string & data)597 void FrontendDelegateDeclarative::OnNewRequest(const std::string& data)
598 {
599     FireSyncEvent("_root", std::string("\"onNewRequest\","), data);
600 }
601 
CallPopPage()602 void FrontendDelegateDeclarative::CallPopPage()
603 {
604     LOGI("CallPopPage begin");
605     Back("", "");
606 }
607 
ResetStagingPage()608 void FrontendDelegateDeclarative::ResetStagingPage()
609 {
610     taskExecutor_->PostTask([resetStagingPage = resetStagingPage_] { resetStagingPage(); }, TaskExecutor::TaskType::JS);
611 }
612 
OnApplicationDestroy(const std::string & packageName)613 void FrontendDelegateDeclarative::OnApplicationDestroy(const std::string& packageName)
614 {
615     taskExecutor_->PostSyncTask(
616         [destroyApplication = destroyApplication_, packageName] { destroyApplication(packageName); },
617         TaskExecutor::TaskType::JS);
618 }
619 
UpdateApplicationState(const std::string & packageName,Frontend::State state)620 void FrontendDelegateDeclarative::UpdateApplicationState(const std::string& packageName, Frontend::State state)
621 {
622     taskExecutor_->PostTask(
623         [updateApplicationState = updateApplicationState_, packageName, state] {
624             updateApplicationState(packageName, state);
625         },
626         TaskExecutor::TaskType::JS);
627 }
628 
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)629 void FrontendDelegateDeclarative::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
630 {
631     taskExecutor_->PostTask(
632         [onWindowDisplayModeChanged = onWindowDisplayModeChanged_, isShownInMultiWindow, data] {
633             onWindowDisplayModeChanged(isShownInMultiWindow, data);
634         },
635         TaskExecutor::TaskType::JS);
636 }
637 
OnSaveAbilityState(std::string & data)638 void FrontendDelegateDeclarative::OnSaveAbilityState(std::string& data)
639 {
640     taskExecutor_->PostSyncTask(
641         [onSaveAbilityState = onSaveAbilityState_, &data] {
642             onSaveAbilityState(data);
643         },
644         TaskExecutor::TaskType::JS);
645 }
646 
OnRestoreAbilityState(const std::string & data)647 void FrontendDelegateDeclarative::OnRestoreAbilityState(const std::string& data)
648 {
649     taskExecutor_->PostTask(
650         [onRestoreAbilityState = onRestoreAbilityState_, data] {
651             onRestoreAbilityState(data);
652         },
653         TaskExecutor::TaskType::JS);
654 }
655 
OnNewWant(const std::string & data)656 void FrontendDelegateDeclarative::OnNewWant(const std::string& data)
657 {
658     taskExecutor_->PostTask(
659         [onNewWant = onNewWant_, data] {
660             onNewWant(data);
661         },
662         TaskExecutor::TaskType::JS);
663 }
664 
FireAsyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)665 void FrontendDelegateDeclarative::FireAsyncEvent(
666     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
667 {
668     LOGD("FireAsyncEvent eventId: %{public}s", eventId.c_str());
669     std::string args = param;
670     args.append(",null").append(",null"); // callback and dom changes
671     if (!jsonArgs.empty()) {
672         args.append(",").append(jsonArgs); // method args
673     }
674     taskExecutor_->PostTask(
675         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
676             auto delegate = weak.Upgrade();
677             if (delegate) {
678                 delegate->asyncEvent_(eventId, args);
679             }
680         },
681         TaskExecutor::TaskType::JS);
682 }
683 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)684 bool FrontendDelegateDeclarative::FireSyncEvent(
685     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
686 {
687     std::string resultStr;
688     FireSyncEvent(eventId, param, jsonArgs, resultStr);
689     return (resultStr == "true");
690 }
691 
692 
FireExternalEvent(const std::string & eventId,const std::string & componentId,const uint32_t nodeId)693 void FrontendDelegateDeclarative::FireExternalEvent(
694     const std::string& eventId, const std::string& componentId, const uint32_t nodeId)
695 {
696     taskExecutor_->PostSyncTask(
697         [weak = AceType::WeakClaim(this), componentId, nodeId] {
698             auto delegate = weak.Upgrade();
699             if (delegate) {
700                 delegate->externalEvent_(componentId, nodeId);
701             }
702         },
703         TaskExecutor::TaskType::JS);
704 }
705 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs,std::string & result)706 void FrontendDelegateDeclarative::FireSyncEvent(
707     const std::string& eventId, const std::string& param, const std::string& jsonArgs, std::string& result)
708 {
709     int32_t callbackId = callbackCnt_++;
710     std::string args = param;
711     args.append("{\"_callbackId\":\"").append(std::to_string(callbackId)).append("\"}").append(",null");
712     if (!jsonArgs.empty()) {
713         args.append(",").append(jsonArgs); // method args
714     }
715     taskExecutor_->PostSyncTask(
716         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
717             auto delegate = weak.Upgrade();
718             if (delegate) {
719                 delegate->syncEvent_(eventId, args);
720             }
721         },
722         TaskExecutor::TaskType::JS);
723 
724     result = jsCallBackResult_[callbackId];
725     LOGD("FireSyncEvent eventId: %{public}s, callbackId: %{public}d", eventId.c_str(), callbackId);
726     jsCallBackResult_.erase(callbackId);
727 }
728 
FireAccessibilityEvent(const AccessibilityEvent & accessibilityEvent)729 void FrontendDelegateDeclarative::FireAccessibilityEvent(const AccessibilityEvent& accessibilityEvent)
730 {
731     jsAccessibilityManager_->SendAccessibilityAsyncEvent(accessibilityEvent);
732 }
733 
InitializeAccessibilityCallback()734 void FrontendDelegateDeclarative::InitializeAccessibilityCallback()
735 {
736     jsAccessibilityManager_->InitializeCallback();
737 }
738 
739 // Start FrontendDelegate overrides.
Push(const std::string & uri,const std::string & params)740 void FrontendDelegateDeclarative::Push(const std::string& uri, const std::string& params)
741 {
742     Push(PageTarget(uri), params);
743 }
744 
Replace(const std::string & uri,const std::string & params)745 void FrontendDelegateDeclarative::Replace(const std::string& uri, const std::string& params)
746 {
747     Replace(PageTarget(uri), params);
748 }
749 
Back(const std::string & uri,const std::string & params)750 void FrontendDelegateDeclarative::Back(const std::string& uri, const std::string& params)
751 {
752     {
753         std::lock_guard<std::mutex> lock(mutex_);
754         if (pageRouteStack_.empty()) {
755             LOGI("page route stack is empty");
756             return;
757         }
758         auto& currentPage = pageRouteStack_.back();
759         if (currentPage.alertCallback) {
760             backUri_ = uri;
761             backParam_ = params;
762             taskExecutor_->PostTask(
763                 [context = pipelineContextHolder_.Get(), dialogProperties = pageRouteStack_.back().dialogProperties,
764                     isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
765                         if (context) {
766                             context->ShowDialog(dialogProperties, isRightToLeft);
767                         }
768                     },
769                 TaskExecutor::TaskType::UI);
770             return;
771         }
772     }
773     BackWithTarget(PageTarget(uri), params);
774 }
775 
Push(const PageTarget & target,const std::string & params)776 void FrontendDelegateDeclarative::Push(const PageTarget& target, const std::string& params)
777 {
778     if (target.url.empty()) {
779         LOGE("router.Push uri is empty");
780         return;
781     }
782     if (isRouteStackFull_) {
783         LOGE("the router stack has reached its max size, you can't push any more pages.");
784         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, target.url);
785         return;
786     }
787 
788     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
789     LOGD("router.Push pagePath = %{private}s", pagePath.c_str());
790     if (!pagePath.empty()) {
791         LoadPage(GenerateNextPageId(), PageTarget(pagePath, target.container), false, params);
792     } else {
793         LOGW("[Engine Log] this uri not support in route push.");
794     }
795 }
796 
Replace(const PageTarget & target,const std::string & params)797 void FrontendDelegateDeclarative::Replace(const PageTarget& target, const std::string& params)
798 {
799     if (target.url.empty()) {
800         LOGE("router.Replace uri is empty");
801         return;
802     }
803 
804     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
805     LOGD("router.Replace pagePath = %{private}s", pagePath.c_str());
806     if (!pagePath.empty()) {
807         LoadReplacePage(GenerateNextPageId(), PageTarget(pagePath, target.container), params);
808     } else {
809         LOGW("[Engine Log] this uri not support in route replace.");
810     }
811 }
812 
PostponePageTransition()813 void FrontendDelegateDeclarative::PostponePageTransition()
814 {
815     taskExecutor_->PostTask(
816         [weak = AceType::WeakClaim(this)] {
817           auto delegate = weak.Upgrade();
818           if (!delegate) {
819               return;
820           }
821           auto pipelineContext = delegate->pipelineContextHolder_.Get();
822           pipelineContext->PostponePageTransition();
823         },
824         TaskExecutor::TaskType::UI);
825 }
826 
LaunchPageTransition()827 void FrontendDelegateDeclarative::LaunchPageTransition()
828 {
829     taskExecutor_->PostTask(
830         [weak = AceType::WeakClaim(this)] {
831           auto delegate = weak.Upgrade();
832           if (!delegate) {
833               return;
834           }
835           auto pipelineContext = delegate->pipelineContextHolder_.Get();
836           pipelineContext->LaunchPageTransition();
837         },
838         TaskExecutor::TaskType::UI);
839 }
840 
BackWithTarget(const PageTarget & target,const std::string & params)841 void FrontendDelegateDeclarative::BackWithTarget(const PageTarget& target, const std::string& params)
842 {
843     LOGD("router.Back path = %{private}s", target.url.c_str());
844     if (target.url.empty()) {
845         std::string pagePath;
846         {
847             std::lock_guard<std::mutex> lock(mutex_);
848             size_t pageRouteSize = pageRouteStack_.size();
849             if (pageRouteSize > 1) {
850                 pageId_ = pageRouteStack_[pageRouteSize - 2].pageId;
851                 if (!params.empty()) {
852                     pageParamMap_[pageId_] = params;
853                 }
854                 // determine whether the previous page needs to be loaded
855                 if (pageRouteStack_[pageRouteSize - 2].isRestore) {
856                     pagePath =
857                         manifestParser_->GetRouter()->GetPagePath(pageRouteStack_[pageRouteSize - 2].url);
858                 }
859             }
860         }
861         if (!pagePath.empty()) {
862             LoadPage(pageId_, PageTarget(pagePath), false, params, true);
863             return;
864         } else {
865             LOGW("back to invalid restore page");
866         }
867         PopPage();
868     } else {
869         std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
870         LOGD("router.Back pagePath = %{private}s", pagePath.c_str());
871         if (!pagePath.empty()) {
872             bool isRestore = false;
873             pageId_ = GetPageIdByUrl(target.url, isRestore);
874             if (isRestore) {
875                 LoadPage(pageId_, PageTarget(pagePath), false, params, true);
876             }
877             if (!params.empty()) {
878                 std::lock_guard<std::mutex> lock(mutex_);
879                 pageParamMap_[pageId_] = params;
880             }
881             PopToPage(pagePath);
882         } else {
883             LOGW("[Engine Log] this uri not support in route Back.");
884         }
885     }
886 }
887 
Clear()888 void FrontendDelegateDeclarative::Clear()
889 {
890     ClearInvisiblePages();
891 }
892 
GetStackSize() const893 int32_t FrontendDelegateDeclarative::GetStackSize() const
894 {
895     std::lock_guard<std::mutex> lock(mutex_);
896     return static_cast<int32_t>(pageRouteStack_.size());
897 }
898 
GetState(int32_t & index,std::string & name,std::string & path)899 void FrontendDelegateDeclarative::GetState(int32_t& index, std::string& name, std::string& path)
900 {
901     std::string url;
902     {
903         std::lock_guard<std::mutex> lock(mutex_);
904         if (pageRouteStack_.empty()) {
905             return;
906         }
907         index = static_cast<int32_t>(pageRouteStack_.size());
908         url = pageRouteStack_.back().url;
909     }
910     auto pos = url.rfind(".js");
911     if (pos == url.length() - 3) {
912         url = url.substr(0, pos);
913     }
914     pos = url.rfind("/");
915     if (pos != std::string::npos) {
916         name = url.substr(pos + 1);
917         path = url.substr(0, pos + 1);
918     }
919 }
920 
GetParams()921 std::string FrontendDelegateDeclarative::GetParams()
922 {
923     if (pageParamMap_.find(pageId_) != pageParamMap_.end()) {
924         return pageParamMap_.find(pageId_)->second;
925     } else {
926         return "";
927     }
928 }
929 
TriggerPageUpdate(int32_t pageId,bool directExecute)930 void FrontendDelegateDeclarative::TriggerPageUpdate(int32_t pageId, bool directExecute)
931 {
932     auto page = GetPage(pageId);
933     if (!page) {
934         return;
935     }
936 
937     auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
938     ACE_DCHECK(jsPage);
939 
940     // Pop all JS command and execute them in UI thread.
941     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
942     jsPage->PopAllCommands(*jsCommands);
943 
944     auto pipelineContext = pipelineContextHolder_.Get();
945     WeakPtr<Framework::JsAcePage> jsPageWeak(jsPage);
946     WeakPtr<PipelineContext> contextWeak(pipelineContext);
947     auto updateTask = [jsPageWeak, contextWeak, jsCommands] {
948         ACE_SCOPED_TRACE("FlushUpdateCommands");
949         auto jsPage = jsPageWeak.Upgrade();
950         auto context = contextWeak.Upgrade();
951         if (!jsPage || !context) {
952             LOGE("Page update failed. page or context is null.");
953             EventReport::SendPageRouterException(PageRouterExcepType::UPDATE_PAGE_ERR);
954             return;
955         }
956         // Flush all JS commands.
957         for (const auto& command : *jsCommands) {
958             command->Execute(jsPage);
959         }
960         if (jsPage->GetDomDocument()) {
961             jsPage->GetDomDocument()->HandleComponentPostBinding();
962         }
963         auto accessibilityManager = context->GetAccessibilityManager();
964         if (accessibilityManager) {
965             accessibilityManager->HandleComponentPostBinding();
966         }
967 
968         jsPage->ClearShowCommand();
969         std::vector<NodeId> dirtyNodes;
970         jsPage->PopAllDirtyNodes(dirtyNodes);
971         for (auto nodeId : dirtyNodes) {
972             auto patchComponent = jsPage->BuildPagePatch(nodeId);
973             if (patchComponent) {
974                 context->ScheduleUpdate(patchComponent);
975             }
976         }
977     };
978 
979     taskExecutor_->PostTask(
980         [updateTask, pipelineContext, directExecute]() {
981             pipelineContext->AddPageUpdateTask(std::move(updateTask), directExecute);
982         },
983         TaskExecutor::TaskType::UI);
984 }
985 
PostJsTask(std::function<void ()> && task)986 void FrontendDelegateDeclarative::PostJsTask(std::function<void()>&& task)
987 {
988     taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS);
989 }
990 
RemoveVisibleChangeNode(NodeId id)991 void FrontendDelegateDeclarative::RemoveVisibleChangeNode(NodeId id)
992 {
993     LOGW("RemoveVisibleChangeNode: Not implemented yet.");
994 }
995 
GetAppID() const996 const std::string& FrontendDelegateDeclarative::GetAppID() const
997 {
998     return manifestParser_->GetAppInfo()->GetAppID();
999 }
1000 
GetAppName() const1001 const std::string& FrontendDelegateDeclarative::GetAppName() const
1002 {
1003     return manifestParser_->GetAppInfo()->GetAppName();
1004 }
1005 
GetVersionName() const1006 const std::string& FrontendDelegateDeclarative::GetVersionName() const
1007 {
1008     return manifestParser_->GetAppInfo()->GetVersionName();
1009 }
1010 
GetVersionCode() const1011 int32_t FrontendDelegateDeclarative::GetVersionCode() const
1012 {
1013     return manifestParser_->GetAppInfo()->GetVersionCode();
1014 }
1015 
ShowToast(const std::string & message,int32_t duration,const std::string & bottom)1016 void FrontendDelegateDeclarative::ShowToast(const std::string& message, int32_t duration, const std::string& bottom)
1017 {
1018     LOGD("FrontendDelegateDeclarative ShowToast.");
1019     int32_t durationTime = std::clamp(duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
1020     auto pipelineContext = pipelineContextHolder_.Get();
1021     bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
1022     taskExecutor_->PostTask(
1023         [durationTime, message, bottom, isRightToLeft, context = pipelineContext] {
1024             ToastComponent::GetInstance().Show(context, message, durationTime, bottom, isRightToLeft);
1025         },
1026         TaskExecutor::TaskType::UI);
1027 }
1028 
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)1029 void FrontendDelegateDeclarative::ShowDialog(const std::string& title, const std::string& message,
1030     const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
1031     const std::set<std::string>& callbacks)
1032 {
1033     std::unordered_map<std::string, EventMarker> callbackMarkers;
1034     if (callbacks.find(COMMON_SUCCESS) != callbacks.end()) {
1035         auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
1036         BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
1037             successEventMarker, [callback, taskExecutor = taskExecutor_](int32_t successType) {
1038                 taskExecutor->PostTask(
1039                     [callback, successType]() { callback(CALLBACK_ERRORCODE_SUCCESS, successType); },
1040                     TaskExecutor::TaskType::JS);
1041             });
1042         callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1043     }
1044 
1045     if (callbacks.find(COMMON_CANCEL) != callbacks.end()) {
1046         auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1047         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1048             cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
1049                 taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
1050                     TaskExecutor::TaskType::JS);
1051             });
1052         callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
1053     }
1054 
1055     if (callbacks.find(COMMON_COMPLETE) != callbacks.end()) {
1056         auto completeEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1057         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1058             completeEventMarker, [callback, taskExecutor = taskExecutor_] {
1059                 taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_COMPLETE, CALLBACK_DATACODE_ZERO); },
1060                     TaskExecutor::TaskType::JS);
1061             });
1062         callbackMarkers.emplace(COMMON_COMPLETE, completeEventMarker);
1063     }
1064 
1065     DialogProperties dialogProperties = {
1066         .title = title,
1067         .content = message,
1068         .autoCancel = autoCancel,
1069         .buttons = buttons,
1070         .callbacks = std::move(callbackMarkers),
1071     };
1072     pipelineContextHolder_.Get()->ShowDialog(dialogProperties, AceApplicationInfo::GetInstance().IsRightToLeft());
1073 }
1074 
ShowActionMenu(const std::string & title,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)1075 void FrontendDelegateDeclarative::ShowActionMenu(const std::string& title, const std::vector<ButtonInfo>& button,
1076     std::function<void(int32_t, int32_t)>&& callback)
1077 {
1078     std::unordered_map<std::string, EventMarker> callbackMarkers;
1079     auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
1080     BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
1081         successEventMarker, [callback, number = button.size(), taskExecutor = taskExecutor_](int32_t successType) {
1082             taskExecutor->PostTask(
1083                 [callback, number, successType]() {
1084                     // if callback index is larger than button's number, cancel button is selected
1085                     if (static_cast<size_t>(successType) == number) {
1086                             callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO);
1087                     } else {
1088                         callback(CALLBACK_ERRORCODE_SUCCESS, successType);
1089                     }
1090                 },
1091             TaskExecutor::TaskType::JS);
1092         });
1093     callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1094 
1095     auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1096     BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1097         cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
1098             taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
1099                 TaskExecutor::TaskType::JS);
1100         });
1101     callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
1102 
1103     DialogProperties dialogProperties = {
1104         .title = title,
1105         .autoCancel = true,
1106         .isMenu = true,
1107         .buttons = button,
1108         .callbacks = std::move(callbackMarkers),
1109     };
1110     ButtonInfo buttonInfo = {
1111         .text = Localization::GetInstance()->GetEntryLetters("common.cancel"),
1112         .textColor = ""
1113     };
1114     dialogProperties.buttons.emplace_back(buttonInfo);
1115     pipelineContextHolder_.Get()->ShowDialog(dialogProperties, AceApplicationInfo::GetInstance().IsRightToLeft());
1116 }
1117 
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)1118 void FrontendDelegateDeclarative::EnableAlertBeforeBackPage(const std::string& message,
1119     std::function<void(int32_t)>&& callback)
1120 {
1121     if (!taskExecutor_) {
1122         LOGE("task executor is null.");
1123         return;
1124     }
1125     std::unordered_map<std::string, EventMarker> callbackMarkers;
1126     auto pipelineContext = pipelineContextHolder_.Get();
1127     auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
1128     BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(successEventMarker,
1129         [weak = AceType::WeakClaim(this), callback, taskExecutor = taskExecutor_](int32_t successType) {
1130             taskExecutor->PostTask(
1131                 [weak, callback, successType]() {
1132                     callback(successType);
1133                     if (!successType) {
1134                         LOGI("dialog choose cancel button, can not back");
1135                         return;
1136                     }
1137                     auto delegate = weak.Upgrade();
1138                     if (!delegate) {
1139                         return;
1140                     }
1141                     delegate->BackWithTarget(PageTarget(delegate->backUri_), delegate->backParam_);
1142                 },
1143                 TaskExecutor::TaskType::JS);
1144         });
1145     callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1146 
1147     std::lock_guard<std::mutex> lock(mutex_);
1148     if (pageRouteStack_.empty()) {
1149         LOGE("page stack is null.");
1150         return;
1151     }
1152 
1153     auto& currentPage = pageRouteStack_.back();
1154     ClearAlertCallback(currentPage);
1155     currentPage.alertCallback = callback;
1156     currentPage.dialogProperties = {
1157         .content = message,
1158         .autoCancel = false,
1159         .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
1160             { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
1161         .callbacks = std::move(callbackMarkers),
1162     };
1163 }
1164 
DisableAlertBeforeBackPage()1165 void FrontendDelegateDeclarative::DisableAlertBeforeBackPage()
1166 {
1167     std::lock_guard<std::mutex> lock(mutex_);
1168     if (pageRouteStack_.empty()) {
1169         LOGE("page stack is null.");
1170         return;
1171     }
1172     auto& currentPage = pageRouteStack_.back();
1173     ClearAlertCallback(currentPage);
1174     currentPage.alertCallback = nullptr;
1175 }
1176 
GetBoundingRectData(NodeId nodeId)1177 Rect FrontendDelegateDeclarative::GetBoundingRectData(NodeId nodeId)
1178 {
1179     Rect rect;
1180     auto task = [context = pipelineContextHolder_.Get(), nodeId, &rect]() {
1181         context->GetBoundingRectData(nodeId, rect);
1182     };
1183     PostSyncTaskToPage(task);
1184     return rect;
1185 }
1186 
GetInspector(NodeId nodeId)1187 std::string FrontendDelegateDeclarative::GetInspector(NodeId nodeId)
1188 {
1189     std::string attrs;
1190     auto task = [weak = WeakClaim(AceType::RawPtr(jsAccessibilityManager_)), nodeId, &attrs]() {
1191         auto accessibilityNodeManager = weak.Upgrade();
1192         if (accessibilityNodeManager) {
1193             attrs = accessibilityNodeManager->GetInspectorNodeById(nodeId);
1194         }
1195     };
1196     PostSyncTaskToPage(task);
1197     return attrs;
1198 }
1199 
SetCallBackResult(const std::string & callBackId,const std::string & result)1200 void FrontendDelegateDeclarative::SetCallBackResult(const std::string& callBackId, const std::string& result)
1201 {
1202     jsCallBackResult_.try_emplace(StringToInt(callBackId), result);
1203 }
1204 
WaitTimer(const std::string & callbackId,const std::string & delay,bool isInterval,bool isFirst)1205 void FrontendDelegateDeclarative::WaitTimer(
1206     const std::string& callbackId, const std::string& delay, bool isInterval, bool isFirst)
1207 {
1208     if (!isFirst) {
1209         auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1210         // If not find the callbackId in map, means this timer already was removed,
1211         // no need create a new cancelableTimer again.
1212         if (timeoutTaskIter == timeoutTaskMap_.end()) {
1213             return;
1214         }
1215     }
1216 
1217     int32_t delayTime = StringToInt(delay);
1218     // CancelableCallback class can only be executed once.
1219     CancelableCallback<void()> cancelableTimer;
1220     cancelableTimer.Reset([callbackId, delay, isInterval, call = timer_] { call(callbackId, delay, isInterval); });
1221     auto result = timeoutTaskMap_.try_emplace(callbackId, cancelableTimer);
1222     if (!result.second) {
1223         result.first->second = cancelableTimer;
1224     }
1225     taskExecutor_->PostDelayedTask(cancelableTimer, TaskExecutor::TaskType::JS, delayTime);
1226 }
1227 
ClearTimer(const std::string & callbackId)1228 void FrontendDelegateDeclarative::ClearTimer(const std::string& callbackId)
1229 {
1230     auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1231     if (timeoutTaskIter != timeoutTaskMap_.end()) {
1232         timeoutTaskIter->second.Cancel();
1233         timeoutTaskMap_.erase(timeoutTaskIter);
1234     } else {
1235         LOGW("ClearTimer callbackId not found");
1236     }
1237 }
1238 
PostSyncTaskToPage(std::function<void ()> && task)1239 void FrontendDelegateDeclarative::PostSyncTaskToPage(std::function<void()>&& task)
1240 {
1241     pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
1242     taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::UI);
1243 }
1244 
AddTaskObserver(std::function<void ()> && task)1245 void FrontendDelegateDeclarative::AddTaskObserver(std::function<void()>&& task)
1246 {
1247     taskExecutor_->AddTaskObserver(std::move(task));
1248 }
1249 
RemoveTaskObserver()1250 void FrontendDelegateDeclarative::RemoveTaskObserver()
1251 {
1252     taskExecutor_->RemoveTaskObserver();
1253 }
1254 
GetAssetContent(const std::string & url,std::string & content)1255 bool FrontendDelegateDeclarative::GetAssetContent(const std::string& url, std::string& content)
1256 {
1257     return GetAssetContentImpl(assetManager_, url, content);
1258 }
1259 
GetAssetContent(const std::string & url,std::vector<uint8_t> & content)1260 bool FrontendDelegateDeclarative::GetAssetContent(const std::string& url, std::vector<uint8_t>& content)
1261 {
1262     return GetAssetContentImpl(assetManager_, url, content);
1263 }
1264 
GetAssetPath(const std::string & url)1265 std::string FrontendDelegateDeclarative::GetAssetPath(const std::string& url)
1266 {
1267     return GetAssetPathImpl(assetManager_, url);
1268 }
1269 
LoadPage(int32_t pageId,const PageTarget & target,bool isMainPage,const std::string & params,bool isRestore)1270 void FrontendDelegateDeclarative::LoadPage(
1271     int32_t pageId, const PageTarget& target, bool isMainPage, const std::string& params, bool isRestore)
1272 {
1273     {
1274         std::lock_guard<std::mutex> lock(mutex_);
1275         pageId_ = pageId;
1276         pageParamMap_[pageId] = params;
1277     }
1278     auto url = target.url;
1279     LOGI("FrontendDelegateDeclarative %{private}p LoadPage[%{public}d]: %{public}s.", this, pageId, url.c_str());
1280     if (pageId == INVALID_PAGE_ID) {
1281         LOGE("FrontendDelegateDeclarative, invalid page id");
1282         EventReport::SendPageRouterException(PageRouterExcepType::LOAD_PAGE_ERR, url);
1283         return;
1284     }
1285     if (isStagingPageExist_) {
1286         LOGE("FrontendDelegateDeclarative, load page failed, waiting for current page loading finish.");
1287         RecyclePageId(pageId);
1288         return;
1289     }
1290     isStagingPageExist_ = true;
1291     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1292     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1293     page->SetPageParams(params);
1294     page->SetFlushCallback([weak = AceType::WeakClaim(this), isMainPage, isRestore](const RefPtr<JsAcePage>& acePage) {
1295         auto delegate = weak.Upgrade();
1296         if (delegate && acePage) {
1297             delegate->FlushPageCommand(acePage, acePage->GetUrl(), isMainPage, isRestore);
1298         }
1299     });
1300     taskExecutor_->PostTask(
1301         [weak = AceType::WeakClaim(this), page, url, isMainPage] {
1302             auto delegate = weak.Upgrade();
1303             if (!delegate) {
1304                 return;
1305             }
1306             delegate->loadJs_(url, page, isMainPage);
1307             page->FlushCommands();
1308             // just make sure the pipelineContext is created.
1309             auto pipeline = delegate->pipelineContextHolder_.Get();
1310             if (delegate->GetMinPlatformVersion() > 0) {
1311                 pipeline->SetMinPlatformVersion(delegate->GetMinPlatformVersion());
1312             }
1313             delegate->taskExecutor_->PostTask(
1314                 [weak, page] {
1315                     auto delegate = weak.Upgrade();
1316                     if (delegate && delegate->pipelineContextHolder_.Get()) {
1317                         delegate->pipelineContextHolder_.Get()->FlushFocus();
1318                     }
1319                     if (page->GetDomDocument()) {
1320                         page->GetDomDocument()->HandlePageLoadFinish();
1321                     }
1322                 },
1323                 TaskExecutor::TaskType::UI);
1324         },
1325         TaskExecutor::TaskType::JS);
1326 }
1327 
OnSurfaceChanged()1328 void FrontendDelegateDeclarative::OnSurfaceChanged()
1329 {
1330     if (mediaQueryInfo_->GetIsInit()) {
1331         mediaQueryInfo_->SetIsInit(false);
1332     }
1333     mediaQueryInfo_->EnsureListenerIdValid();
1334     OnMediaQueryUpdate();
1335 }
1336 
OnMediaQueryUpdate()1337 void FrontendDelegateDeclarative::OnMediaQueryUpdate()
1338 {
1339     if (mediaQueryInfo_->GetIsInit()) {
1340         return;
1341     }
1342 
1343     taskExecutor_->PostTask(
1344         [weak = AceType::WeakClaim(this)] {
1345             auto delegate = weak.Upgrade();
1346             if (!delegate) {
1347                 return;
1348             }
1349             const auto& info = delegate->mediaQueryInfo_->GetMediaQueryInfo();
1350             // request css mediaquery
1351             std::string param("\"viewsizechanged\",");
1352             param.append(info);
1353             delegate->asyncEvent_("_root", param);
1354 
1355             // request js mediaquery
1356             const auto& listenerId = delegate->mediaQueryInfo_->GetListenerId();
1357             delegate->mediaQueryCallback_(listenerId, info);
1358             delegate->mediaQueryInfo_->ResetListenerId();
1359         },
1360         TaskExecutor::TaskType::JS);
1361 }
1362 
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage,bool isRestore)1363 void FrontendDelegateDeclarative::OnPageReady(
1364     const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage, bool isRestore)
1365 {
1366     LOGI("OnPageReady url = %{private}s", url.c_str());
1367     // Pop all JS command and execute them in UI thread.
1368     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1369     page->PopAllCommands(*jsCommands);
1370 
1371     auto pipelineContext = pipelineContextHolder_.Get();
1372     page->SetPipelineContext(pipelineContext);
1373     taskExecutor_->PostTask(
1374         [weak = AceType::WeakClaim(this), page, url, jsCommands, isMainPage, isRestore] {
1375             auto delegate = weak.Upgrade();
1376             if (!delegate) {
1377                 return;
1378             }
1379             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1380             // Flush all JS commands.
1381             for (const auto& command : *jsCommands) {
1382                 command->Execute(page);
1383             }
1384             // Just clear all dirty nodes.
1385             page->ClearAllDirtyNodes();
1386             if (page->GetDomDocument()) {
1387                 page->GetDomDocument()->HandleComponentPostBinding();
1388             }
1389             if (pipelineContext->GetAccessibilityManager()) {
1390                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1391             }
1392             if (isRestore) {
1393                 delegate->RestorePopPage(page, url);
1394                 return;
1395             }
1396             if (pipelineContext->CanPushPage()) {
1397                 if (!isMainPage) {
1398                     delegate->OnPageHide();
1399                 }
1400                 delegate->OnPrePageChange(page);
1401                 pipelineContext->PushPage(page->BuildPage(url), page->GetStageElement());
1402                 delegate->OnPushPageSuccess(page, url);
1403                 delegate->SetCurrentPage(page->GetPageId());
1404                 delegate->OnMediaQueryUpdate();
1405             } else {
1406                 // This page has been loaded but become useless now, the corresponding js instance
1407                 // must be destroyed to avoid memory leak.
1408                 delegate->OnPageDestroy(page->GetPageId());
1409                 delegate->ResetStagingPage();
1410             }
1411             delegate->isStagingPageExist_ = false;
1412             if (isMainPage) {
1413                 delegate->OnPageShow();
1414             }
1415         },
1416         TaskExecutor::TaskType::UI);
1417 }
1418 
OnPrePageChange(const RefPtr<JsAcePage> & page)1419 void FrontendDelegateDeclarative::OnPrePageChange(const RefPtr<JsAcePage>& page)
1420 {
1421     LOGI("FrontendDelegateDeclarative OnPrePageChange");
1422     if (page && page->GetDomDocument() && jsAccessibilityManager_) {
1423         jsAccessibilityManager_->SetRootNodeId(page->GetDomDocument()->GetRootNodeId());
1424     }
1425 }
1426 
FlushPageCommand(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage,bool isRestore)1427 void FrontendDelegateDeclarative::FlushPageCommand(
1428     const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage, bool isRestore)
1429 {
1430     if (!page) {
1431         return;
1432     }
1433     LOGI("FlushPageCommand FragmentCount(%{public}d)", page->FragmentCount());
1434     if (page->FragmentCount() == 1) {
1435         OnPageReady(page, url, isMainPage, isRestore);
1436     } else {
1437         TriggerPageUpdate(page->GetPageId());
1438     }
1439 }
1440 
AddPageLocked(const RefPtr<JsAcePage> & page)1441 void FrontendDelegateDeclarative::AddPageLocked(const RefPtr<JsAcePage>& page)
1442 {
1443     auto result = pageMap_.try_emplace(page->GetPageId(), page);
1444     if (!result.second) {
1445         LOGW("the page has already in the map");
1446     }
1447 }
1448 
SetCurrentPage(int32_t pageId)1449 void FrontendDelegateDeclarative::SetCurrentPage(int32_t pageId)
1450 {
1451     LOGD("FrontendDelegateDeclarative SetCurrentPage pageId=%{private}d", pageId);
1452     auto page = GetPage(pageId);
1453     if (page != nullptr) {
1454         jsAccessibilityManager_->SetVersion(AccessibilityVersion::JS_DECLARATIVE_VERSION);
1455         jsAccessibilityManager_->SetRunningPage(page);
1456         taskExecutor_->PostTask([updatePage = updatePage_, page] { updatePage(page); }, TaskExecutor::TaskType::JS);
1457     } else {
1458         LOGE("FrontendDelegateDeclarative SetCurrentPage page is null.");
1459     }
1460 }
1461 
OnPushPageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1462 void FrontendDelegateDeclarative::OnPushPageSuccess(
1463     const RefPtr<JsAcePage>& page, const std::string& url)
1464 {
1465     std::lock_guard<std::mutex> lock(mutex_);
1466     AddPageLocked(page);
1467     pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url });
1468     if (pageRouteStack_.size() >= MAX_ROUTER_STACK) {
1469         isRouteStackFull_ = true;
1470         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, page->GetUrl());
1471     }
1472     LOGI("OnPushPageSuccess size=%{private}zu,pageId=%{private}d,url=%{private}s", pageRouteStack_.size(),
1473         pageRouteStack_.back().pageId, pageRouteStack_.back().url.c_str());
1474 }
1475 
OnPopToPageSuccess(const std::string & url)1476 void FrontendDelegateDeclarative::OnPopToPageSuccess(const std::string& url)
1477 {
1478     std::lock_guard<std::mutex> lock(mutex_);
1479     while (!pageRouteStack_.empty()) {
1480         if (pageRouteStack_.back().url == url) {
1481             break;
1482         }
1483         OnPageDestroy(pageRouteStack_.back().pageId);
1484         pageMap_.erase(pageRouteStack_.back().pageId);
1485         pageParamMap_.erase(pageRouteStack_.back().pageId);
1486         ClearAlertCallback(pageRouteStack_.back());
1487         pageRouteStack_.pop_back();
1488     }
1489 
1490     if (isRouteStackFull_) {
1491         isRouteStackFull_ = false;
1492     }
1493 }
1494 
PopToPage(const std::string & url)1495 void FrontendDelegateDeclarative::PopToPage(const std::string& url)
1496 {
1497     LOGD("FrontendDelegateDeclarative PopToPage url = %{private}s", url.c_str());
1498     taskExecutor_->PostTask(
1499         [weak = AceType::WeakClaim(this), url] {
1500             auto delegate = weak.Upgrade();
1501             if (!delegate) {
1502                 return;
1503             }
1504             auto pageId = delegate->GetPageIdByUrl(url);
1505             if (pageId == INVALID_PAGE_ID) {
1506                 return;
1507             }
1508             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1509             if (!pipelineContext->CanPopPage()) {
1510                 delegate->ResetStagingPage();
1511                 return;
1512             }
1513             delegate->OnPageHide();
1514             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1515             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1516                 [weak, url, pageId](
1517                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1518                     auto delegate = weak.Upgrade();
1519                     if (delegate) {
1520                         delegate->PopToPageTransitionListener(event, url, pageId);
1521                     }
1522                 });
1523             pipelineContext->PopToPage(pageId);
1524         },
1525         TaskExecutor::TaskType::UI);
1526 }
1527 
PopToPageTransitionListener(const TransitionEvent & event,const std::string & url,int32_t pageId)1528 void FrontendDelegateDeclarative::PopToPageTransitionListener(
1529     const TransitionEvent& event, const std::string& url, int32_t pageId)
1530 {
1531     if (event == TransitionEvent::POP_END) {
1532         OnPopToPageSuccess(url);
1533         SetCurrentPage(pageId);
1534         OnPageShow();
1535         OnMediaQueryUpdate();
1536     }
1537 }
1538 
OnPopPageSuccess()1539 int32_t FrontendDelegateDeclarative::OnPopPageSuccess()
1540 {
1541     std::lock_guard<std::mutex> lock(mutex_);
1542     pageMap_.erase(pageRouteStack_.back().pageId);
1543     pageParamMap_.erase(pageRouteStack_.back().pageId);
1544     ClearAlertCallback(pageRouteStack_.back());
1545     pageRouteStack_.pop_back();
1546     if (isRouteStackFull_) {
1547         isRouteStackFull_ = false;
1548     }
1549     if (!pageRouteStack_.empty()) {
1550         LOGI("OnPopPageSuccess: pop to page %{private}s", pageRouteStack_.back().url.c_str());
1551         return pageRouteStack_.back().pageId;
1552     }
1553     return INVALID_PAGE_ID;
1554 }
1555 
PopPage()1556 void FrontendDelegateDeclarative::PopPage()
1557 {
1558     taskExecutor_->PostTask(
1559         [weak = AceType::WeakClaim(this)] {
1560             auto delegate = weak.Upgrade();
1561             if (!delegate) {
1562                 return;
1563             }
1564             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1565             if (delegate->GetStackSize() == 1) {
1566                 if (delegate->disallowPopLastPage_) {
1567                     LOGW("Not allow back because this is the last page!");
1568                     return;
1569                 }
1570                 delegate->OnPageHide();
1571                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1572                 delegate->OnPopPageSuccess();
1573                 pipelineContext->Finish();
1574                 return;
1575             }
1576             if (!pipelineContext->CanPopPage()) {
1577                 delegate->ResetStagingPage();
1578                 return;
1579             }
1580             delegate->OnPageHide();
1581             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1582             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1583                 [weak, destroyPageId = delegate->GetRunningPageId()](
1584                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1585                     auto delegate = weak.Upgrade();
1586                     if (delegate) {
1587                         delegate->PopPageTransitionListener(event, destroyPageId);
1588                     }
1589                 });
1590             pipelineContext->PopPage();
1591         },
1592         TaskExecutor::TaskType::UI);
1593 }
1594 
PopPageTransitionListener(const TransitionEvent & event,int32_t destroyPageId)1595 void FrontendDelegateDeclarative::PopPageTransitionListener(
1596     const TransitionEvent& event, int32_t destroyPageId)
1597 {
1598     if (event == TransitionEvent::POP_END) {
1599         OnPageDestroy(destroyPageId);
1600         auto pageId = OnPopPageSuccess();
1601         SetCurrentPage(pageId);
1602         OnPageShow();
1603         OnMediaQueryUpdate();
1604     }
1605 }
1606 
RestorePopPage(const RefPtr<JsAcePage> & page,const std::string & url)1607 void FrontendDelegateDeclarative::RestorePopPage(const RefPtr<JsAcePage>& page, const std::string& url)
1608 {
1609     taskExecutor_->PostTask(
1610         [weak = AceType::WeakClaim(this), page, url] {
1611             auto delegate = weak.Upgrade();
1612             if (!delegate) {
1613                 return;
1614             }
1615             LOGI("RestorePopPage begin");
1616             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1617             bool isLastPage = false;
1618             if (delegate->GetStackSize() == 1) {
1619                 if (delegate->disallowPopLastPage_) {
1620                     LOGW("Not allow back because this is the last page!");
1621                     return;
1622                 }
1623 
1624                 isLastPage = true;
1625                 delegate->OnPageHide();
1626                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1627                 delegate->OnPopPageSuccess();
1628                 pipelineContext->Finish();
1629                 return;
1630             }
1631             delegate->OnPageHide();
1632             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1633             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1634                 [weak, url, page](
1635                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1636                     auto delegate = weak.Upgrade();
1637                     if (delegate) {
1638                         delegate->RestorePageTransitionListener(event, url, page);
1639                     }
1640                 });
1641             pipelineContext->RestorePopPage(page->BuildPage(url));
1642             delegate->isStagingPageExist_ = false;
1643         },
1644         TaskExecutor::TaskType::UI);
1645 }
1646 
RestorePageTransitionListener(const TransitionEvent & event,const std::string & url,const RefPtr<JsAcePage> & page)1647 void FrontendDelegateDeclarative::RestorePageTransitionListener(
1648     const TransitionEvent& event, const std::string& url, const RefPtr<JsAcePage>& page)
1649 {
1650     if (event == TransitionEvent::POP_END) {
1651         LOGI("RestorePageTransitionListener %{public}s", url.c_str());
1652         OnPopToPageSuccess(url);
1653         {
1654             std::lock_guard<std::mutex> lock(mutex_);
1655             AddPageLocked(page);
1656             pageRouteStack_.back().isRestore = false;
1657         }
1658         SetCurrentPage(GetPageIdByUrl(url));
1659         OnPageShow();
1660         OnMediaQueryUpdate();
1661     }
1662 }
1663 
OnClearInvisiblePagesSuccess()1664 int32_t FrontendDelegateDeclarative::OnClearInvisiblePagesSuccess()
1665 {
1666     std::lock_guard<std::mutex> lock(mutex_);
1667     PageInfo pageInfo = std::move(pageRouteStack_.back());
1668     pageRouteStack_.pop_back();
1669     for (const auto& info : pageRouteStack_) {
1670         ClearAlertCallback(info);
1671         OnPageDestroy(info.pageId);
1672         pageMap_.erase(info.pageId);
1673         pageParamMap_.erase(info.pageId);
1674     }
1675     pageRouteStack_.clear();
1676     int32_t resPageId = pageInfo.pageId;
1677     pageRouteStack_.emplace_back(std::move(pageInfo));
1678     if (isRouteStackFull_) {
1679         isRouteStackFull_ = false;
1680     }
1681     return resPageId;
1682 }
1683 
ClearInvisiblePages()1684 void FrontendDelegateDeclarative::ClearInvisiblePages()
1685 {
1686     taskExecutor_->PostTask(
1687         [weak = AceType::WeakClaim(this)] {
1688             auto delegate = weak.Upgrade();
1689             if (!delegate) {
1690                 return;
1691             }
1692             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1693             if (pipelineContext->ClearInvisiblePages()) {
1694                 auto pageId = delegate->OnClearInvisiblePagesSuccess();
1695                 delegate->SetCurrentPage(pageId);
1696             }
1697         },
1698         TaskExecutor::TaskType::UI);
1699 }
1700 
OnReplacePageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1701 void FrontendDelegateDeclarative::OnReplacePageSuccess(
1702     const RefPtr<JsAcePage>& page, const std::string& url)
1703 {
1704     if (!page) {
1705         return;
1706     }
1707     std::lock_guard<std::mutex> lock(mutex_);
1708     AddPageLocked(page);
1709     if (!pageRouteStack_.empty()) {
1710         pageMap_.erase(pageRouteStack_.back().pageId);
1711         pageParamMap_.erase(pageRouteStack_.back().pageId);
1712         ClearAlertCallback(pageRouteStack_.back());
1713         pageRouteStack_.pop_back();
1714     }
1715     pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url});
1716 }
1717 
ReplacePage(const RefPtr<JsAcePage> & page,const std::string & url)1718 void FrontendDelegateDeclarative::ReplacePage(
1719     const RefPtr<JsAcePage>& page, const std::string& url)
1720 {
1721     LOGI("ReplacePage url = %{private}s", url.c_str());
1722     // Pop all JS command and execute them in UI thread.
1723     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1724     page->PopAllCommands(*jsCommands);
1725 
1726     auto pipelineContext = pipelineContextHolder_.Get();
1727     page->SetPipelineContext(pipelineContext);
1728     taskExecutor_->PostTask(
1729         [weak = AceType::WeakClaim(this), page, url, jsCommands] {
1730             auto delegate = weak.Upgrade();
1731             if (!delegate) {
1732                 return;
1733             }
1734             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1735             // Flush all JS commands.
1736             for (const auto& command : *jsCommands) {
1737                 command->Execute(page);
1738             }
1739             // Just clear all dirty nodes.
1740             page->ClearAllDirtyNodes();
1741             page->GetDomDocument()->HandleComponentPostBinding();
1742             pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1743             if (pipelineContext->CanReplacePage()) {
1744                 delegate->OnPageHide();
1745                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1746                 delegate->OnPrePageChange(page);
1747                 pipelineContext->ReplacePage(page->BuildPage(url), page->GetStageElement());
1748                 delegate->OnReplacePageSuccess(page, url);
1749                 delegate->SetCurrentPage(page->GetPageId());
1750                 delegate->OnMediaQueryUpdate();
1751             } else {
1752                 // This page has been loaded but become useless now, the corresponding js instance
1753                 // must be destroyed to avoid memory leak.
1754                 delegate->OnPageDestroy(page->GetPageId());
1755                 delegate->ResetStagingPage();
1756             }
1757             delegate->isStagingPageExist_ = false;
1758         },
1759         TaskExecutor::TaskType::UI);
1760 }
1761 
LoadReplacePage(int32_t pageId,const PageTarget & target,const std::string & params)1762 void FrontendDelegateDeclarative::LoadReplacePage(int32_t pageId, const PageTarget& target, const std::string& params)
1763 {
1764     {
1765         std::lock_guard<std::mutex> lock(mutex_);
1766         pageId_ = pageId;
1767         pageParamMap_[pageId] = params;
1768     }
1769     auto url = target.url;
1770     LOGI("FrontendDelegateDeclarative LoadReplacePage[%{private}d]: %{private}s.", pageId, url.c_str());
1771     if (pageId == INVALID_PAGE_ID) {
1772         LOGW("FrontendDelegateDeclarative, invalid page id");
1773         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1774         return;
1775     }
1776     if (isStagingPageExist_) {
1777         LOGW("FrontendDelegateDeclarative, replace page failed, waiting for current page loading finish.");
1778         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1779         return;
1780     }
1781     isStagingPageExist_ = true;
1782     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1783     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1784     page->SetPageParams(params);
1785     taskExecutor_->PostTask(
1786         [page, url, weak = AceType::WeakClaim(this)] {
1787             auto delegate = weak.Upgrade();
1788             if (delegate) {
1789                 delegate->loadJs_(url, page, false);
1790                 delegate->ReplacePage(page, url);
1791             }
1792         },
1793         TaskExecutor::TaskType::JS);
1794 }
1795 
SetColorMode(ColorMode colorMode)1796 void FrontendDelegateDeclarative::SetColorMode(ColorMode colorMode)
1797 {
1798     OnMediaQueryUpdate();
1799 }
1800 
RebuildAllPages()1801 void FrontendDelegateDeclarative::RebuildAllPages()
1802 {
1803     std::unordered_map<int32_t, RefPtr<JsAcePage>> pages;
1804     {
1805         std::lock_guard<std::mutex> lock(mutex_);
1806         pages.insert(pageMap_.begin(), pageMap_.end());
1807     }
1808     for (const auto& [pageId, page] : pages) {
1809         page->FireDeclarativeOnPageRefreshCallback();
1810         TriggerPageUpdate(page->GetPageId(), true);
1811     }
1812 }
1813 
OnPageShow()1814 void FrontendDelegateDeclarative::OnPageShow()
1815 {
1816     auto pageId = GetRunningPageId();
1817     auto page = GetPage(pageId);
1818     if (page) {
1819         page->FireDeclarativeOnPageAppearCallback();
1820     }
1821     FireAsyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
1822 }
1823 
OnPageHide()1824 void FrontendDelegateDeclarative::OnPageHide()
1825 {
1826     auto pageId = GetRunningPageId();
1827     auto page = GetPage(pageId);
1828     if (page) {
1829         page->FireDeclarativeOnPageDisAppearCallback();
1830     }
1831     FireAsyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
1832 }
1833 
ClearAlertCallback(PageInfo pageInfo)1834 void FrontendDelegateDeclarative::ClearAlertCallback(PageInfo pageInfo)
1835 {
1836     if (pageInfo.alertCallback) {
1837         // notify to clear js reference
1838         pageInfo.alertCallback(static_cast<int32_t>(AlertState::RECOVERY));
1839         pageInfo.alertCallback = nullptr;
1840     }
1841 }
1842 
OnPageDestroy(int32_t pageId)1843 void FrontendDelegateDeclarative::OnPageDestroy(int32_t pageId)
1844 {
1845     taskExecutor_->PostTask(
1846         [weak = AceType::WeakClaim(this), pageId] {
1847             auto delegate = weak.Upgrade();
1848             if (delegate) {
1849                 delegate->destroyPage_(pageId);
1850                 delegate->RecyclePageId(pageId);
1851             }
1852         },
1853         TaskExecutor::TaskType::JS);
1854 }
1855 
GetRunningPageId() const1856 int32_t FrontendDelegateDeclarative::GetRunningPageId() const
1857 {
1858     std::lock_guard<std::mutex> lock(mutex_);
1859     if (pageRouteStack_.empty()) {
1860         return INVALID_PAGE_ID;
1861     }
1862     return pageRouteStack_.back().pageId;
1863 }
1864 
GetRunningPageUrl() const1865 std::string FrontendDelegateDeclarative::GetRunningPageUrl() const
1866 {
1867     std::lock_guard<std::mutex> lock(mutex_);
1868     if (pageRouteStack_.empty()) {
1869         return std::string();
1870     }
1871     const auto& pageUrl = pageRouteStack_.back().url;
1872     auto pos = pageUrl.rfind(".js");
1873     if (pos == pageUrl.length() - 3) {
1874         return pageUrl.substr(0, pos);
1875     }
1876     return pageUrl;
1877 }
1878 
GetPageIdByUrl(const std::string & url,bool isRestore)1879 int32_t FrontendDelegateDeclarative::GetPageIdByUrl(const std::string& url, bool isRestore)
1880 {
1881     std::lock_guard<std::mutex> lock(mutex_);
1882     auto pageIter = std::find_if(std::rbegin(pageRouteStack_), std::rend(pageRouteStack_),
1883         [&url](const PageInfo& pageRoute) { return url == pageRoute.url; });
1884     if (pageIter != std::rend(pageRouteStack_)) {
1885         LOGD("GetPageIdByUrl pageId=%{private}d url=%{private}s", pageIter->pageId, url.c_str());
1886         isRestore = pageIter->isRestore;
1887         return pageIter->pageId;
1888     }
1889     return INVALID_PAGE_ID;
1890 }
1891 
GetPage(int32_t pageId) const1892 RefPtr<JsAcePage> FrontendDelegateDeclarative::GetPage(int32_t pageId) const
1893 {
1894     std::lock_guard<std::mutex> lock(mutex_);
1895     auto itPage = pageMap_.find(pageId);
1896     if (itPage == pageMap_.end()) {
1897         LOGE("the page is not in the map");
1898         return nullptr;
1899     }
1900     return itPage->second;
1901 }
1902 
RegisterFont(const std::string & familyName,const std::string & familySrc)1903 void FrontendDelegateDeclarative::RegisterFont(const std::string& familyName, const std::string& familySrc)
1904 {
1905     pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc);
1906 }
1907 
HandleImage(const std::string & src,std::function<void (bool,int32_t,int32_t)> && callback)1908 void FrontendDelegateDeclarative::HandleImage(
1909     const std::string& src, std::function<void(bool, int32_t, int32_t)>&& callback)
1910 {
1911     LOGW("Not implement in declarative frontend.");
1912 }
1913 
PushJsCallbackToRenderNode(NodeId id,double ratio,std::function<void (bool,double)> && callback)1914 void FrontendDelegateDeclarative::PushJsCallbackToRenderNode(NodeId id, double ratio,
1915     std::function<void(bool, double)>&& callback)
1916 {
1917     LOGW("Not implement in declarative frontend.");
1918 }
1919 
RequestAnimationFrame(const std::string & callbackId)1920 void FrontendDelegateDeclarative::RequestAnimationFrame(const std::string& callbackId)
1921 {
1922     CancelableCallback<void()> cancelableTask;
1923     cancelableTask.Reset([callbackId, call = requestAnimationCallback_, weak = AceType::WeakClaim(this)] {
1924         auto delegate = weak.Upgrade();
1925         if (delegate && call) {
1926             call(callbackId, delegate->GetSystemRealTime());
1927         }
1928     });
1929     animationFrameTaskMap_.try_emplace(callbackId, cancelableTask);
1930     animationFrameTaskIds_.emplace(callbackId);
1931 }
1932 
GetSystemRealTime()1933 uint64_t FrontendDelegateDeclarative::GetSystemRealTime()
1934 {
1935     struct timespec ts;
1936     clock_gettime(CLOCK_REALTIME, &ts);
1937     return ts.tv_sec * TO_MILLI + ts.tv_nsec / NANO_TO_MILLI;
1938 }
1939 
CancelAnimationFrame(const std::string & callbackId)1940 void FrontendDelegateDeclarative::CancelAnimationFrame(const std::string& callbackId)
1941 {
1942     auto animationTaskIter = animationFrameTaskMap_.find(callbackId);
1943     if (animationTaskIter != animationFrameTaskMap_.end()) {
1944         animationTaskIter->second.Cancel();
1945         animationFrameTaskMap_.erase(animationTaskIter);
1946     } else {
1947         LOGW("cancelAnimationFrame callbackId not found");
1948     }
1949 }
1950 
FlushAnimationTasks()1951 void FrontendDelegateDeclarative::FlushAnimationTasks()
1952 {
1953     while (!animationFrameTaskIds_.empty()) {
1954         const auto& callbackId = animationFrameTaskIds_.front();
1955         if (!callbackId.empty()) {
1956             auto taskIter = animationFrameTaskMap_.find(callbackId);
1957             if (taskIter != animationFrameTaskMap_.end()) {
1958                 taskExecutor_->PostTask(taskIter->second, TaskExecutor::TaskType::JS);
1959             }
1960         }
1961         animationFrameTaskIds_.pop();
1962     }
1963 }
1964 
GetAnimationJsTask()1965 SingleTaskExecutor FrontendDelegateDeclarative::GetAnimationJsTask()
1966 {
1967     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::JS);
1968 }
1969 
GetUiTask()1970 SingleTaskExecutor FrontendDelegateDeclarative::GetUiTask()
1971 {
1972     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::UI);
1973 }
1974 
AttachPipelineContext(const RefPtr<PipelineContext> & context)1975 void FrontendDelegateDeclarative::AttachPipelineContext(const RefPtr<PipelineContext>& context)
1976 {
1977     context->SetOnPageShow([weak = AceType::WeakClaim(this)] {
1978         auto delegate = weak.Upgrade();
1979         if (delegate) {
1980             delegate->OnPageShow();
1981         }
1982     });
1983     context->SetAnimationCallback([weak = AceType::WeakClaim(this)] {
1984         auto delegate = weak.Upgrade();
1985         if (delegate) {
1986             delegate->FlushAnimationTasks();
1987         }
1988     });
1989     pipelineContextHolder_.Attach(context);
1990     jsAccessibilityManager_->SetPipelineContext(context);
1991     jsAccessibilityManager_->InitializeCallback();
1992 }
1993 
GetPipelineContext()1994 RefPtr<PipelineContext> FrontendDelegateDeclarative::GetPipelineContext()
1995 {
1996     return pipelineContextHolder_.Get();
1997 }
1998 
RestoreRouterStack(const std::string & contentInfo)1999 std::string FrontendDelegateDeclarative::RestoreRouterStack(const std::string& contentInfo)
2000 {
2001     LOGI("FrontendDelegateDeclarative::RestoreRouterStack: contentInfo = %{public}s", contentInfo.c_str());
2002     auto jsonContentInfo = JsonUtil::ParseJsonString(contentInfo);
2003     if (!jsonContentInfo->IsValid() || !jsonContentInfo->IsObject()) {
2004         LOGW("restore contentInfo is invalid");
2005         return "";
2006     }
2007     // restore node info
2008     auto jsonNodeInfo = jsonContentInfo->GetValue("nodeInfo");
2009     auto pipelineContext = pipelineContextHolder_.Get();
2010     pipelineContext->RestoreNodeInfo(std::move(jsonNodeInfo));
2011     // restore stack info
2012     std::lock_guard<std::mutex> lock(mutex_);
2013     auto routerStack = jsonContentInfo->GetValue("stackInfo");
2014     if (!routerStack->IsValid() || !routerStack->IsArray()) {
2015         LOGW("restore router stack is invalid");
2016         return "";
2017     }
2018     int32_t stackSize = routerStack->GetArraySize();
2019     if (stackSize < 1) {
2020         LOGW("restore stack size is invalid");
2021         return "";
2022     }
2023     for (int32_t index = 0; index < stackSize - 1; ++index) {
2024         std::string url = routerStack->GetArrayItem(index)->ToString();
2025         // remove 2 useless character, as "XXX" to XXX
2026         pageRouteStack_.emplace_back(
2027             PageInfo { GenerateNextPageId(), url.substr(1, url.size() - 2), true });
2028     }
2029     std::string startUrl = routerStack->GetArrayItem(stackSize - 1)->ToString();
2030     // remove 5 useless character, as "XXX.js" to XXX
2031     return startUrl.substr(1, startUrl.size() - 5);
2032 }
2033 
GetContentInfo()2034 std::string FrontendDelegateDeclarative::GetContentInfo()
2035 {
2036     auto jsonContentInfo = JsonUtil::Create(true);
2037 
2038     {
2039         std::lock_guard<std::mutex> lock(mutex_);
2040         auto jsonRouterStack = JsonUtil::CreateArray(false);
2041         for (size_t index = 0; index < pageRouteStack_.size(); ++index) {
2042             jsonRouterStack->Put("", pageRouteStack_[index].url.c_str());
2043         }
2044         jsonContentInfo->Put("stackInfo", jsonRouterStack);
2045     }
2046 
2047     auto pipelineContext = pipelineContextHolder_.Get();
2048     jsonContentInfo->Put("nodeInfo", pipelineContext->GetStoredNodeInfo());
2049 
2050     return jsonContentInfo->ToString();
2051 }
2052 
2053 } // namespace OHOS::Ace::Framework
2054