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