• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/plugin_frontend/plugin_frontend_delegate.h"
17 
18 #include "base/log/event_report.h"
19 #include "base/resource/ace_res_config.h"
20 #include "core/components/toast/toast_component.h"
21 
22 namespace OHOS::Ace::Framework {
23 namespace {
24 constexpr uint8_t MIN_ROUT_COUNT = 2;
25 constexpr uint8_t JS_HEADER_OFFSET = 3;
26 constexpr int32_t INVALID_PAGE_ID = -1;
27 constexpr int32_t MAX_ROUTER_STACK = 32;
28 constexpr int32_t TOAST_TIME_MAX = 10000;    // ms
29 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
30 constexpr int32_t MAX_PAGE_ID_SIZE = sizeof(uint64_t) * 8;
31 constexpr int32_t NANO_TO_MILLI = 1000000; // nanosecond to millisecond
32 constexpr int32_t TO_MILLI = 1000;         // second to millisecond
33 
34 const char MANIFEST_JSON[] = "manifest.json";
35 const char FILE_TYPE_JSON[] = ".json";
36 const char I18N_FOLDER[] = "i18n/";
37 const char RESOURCES_FOLDER[] = "resources/";
38 const char STYLES_FOLDER[] = "styles/";
39 const char I18N_FILE_SUFFIX[] = "/properties/string.json";
40 } // namespace
41 
GenerateNextPageId()42 int32_t PluginFrontendDelegate::GenerateNextPageId()
43 {
44     for (int32_t idx = 0; idx < MAX_PAGE_ID_SIZE; ++idx) {
45         uint64_t bitMask = (1ULL << idx);
46         if ((bitMask & pageIdPool_.fetch_or(bitMask, std::memory_order_relaxed)) == 0) {
47             return idx;
48         }
49     }
50     return INVALID_PAGE_ID;
51 }
52 
RecyclePageId(int32_t pageId)53 void PluginFrontendDelegate::RecyclePageId(int32_t pageId)
54 {
55     if (pageId < 0 || pageId >= MAX_PAGE_ID_SIZE) {
56         return;
57     }
58     uint64_t bitMask = (1ULL << pageId);
59     pageIdPool_.fetch_and(~bitMask, std::memory_order_relaxed);
60 }
61 
PluginFrontendDelegate(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)62 PluginFrontendDelegate::PluginFrontendDelegate(const RefPtr<TaskExecutor>& taskExecutor,
63     const LoadJsCallback& loadCallback, const JsMessageDispatcherSetterCallback& transferCallback,
64     const EventCallback& asyncEventCallback, const EventCallback& syncEventCallback,
65     const UpdatePageCallback& updatePageCallback, const ResetStagingPageCallback& resetLoadingPageCallback,
66     const DestroyPageCallback& destroyPageCallback, const DestroyApplicationCallback& destroyApplicationCallback,
67     const UpdateApplicationStateCallback& updateApplicationStateCallback,
68     const TimerCallback& timerCallback, const MediaQueryCallback& mediaQueryCallback,
69     const RequestAnimationCallback& requestAnimationCallback, const JsCallback& jsCallback,
70     const OnWindowDisplayModeChangedCallBack& onWindowDisplayModeChangedCallBack,
71     const OnConfigurationUpdatedCallBack& onConfigurationUpdatedCallBack,
72     const OnSaveAbilityStateCallBack& onSaveAbilityStateCallBack,
73     const OnRestoreAbilityStateCallBack& onRestoreAbilityStateCallBack,
74     const OnNewWantCallBack& onNewWantCallBack, const OnActiveCallBack& onActiveCallBack,
75     const OnInactiveCallBack& onInactiveCallBack, const OnMemoryLevelCallBack& onMemoryLevelCallBack,
76     const OnStartContinuationCallBack& onStartContinuationCallBack,
77     const OnCompleteContinuationCallBack& onCompleteContinuationCallBack,
78     const OnRemoteTerminatedCallBack& onRemoteTerminatedCallBack,
79     const OnSaveDataCallBack& onSaveDataCallBack,
80     const OnRestoreDataCallBack& onRestoreDataCallBack)
81     : loadJs_(loadCallback), dispatcherCallback_(transferCallback), asyncEvent_(asyncEventCallback),
82       syncEvent_(syncEventCallback), updatePage_(updatePageCallback), resetStagingPage_(resetLoadingPageCallback),
83       destroyPage_(destroyPageCallback), destroyApplication_(destroyApplicationCallback),
84       updateApplicationState_(updateApplicationStateCallback), timer_(timerCallback),
85       mediaQueryCallback_(mediaQueryCallback), requestAnimationCallback_(requestAnimationCallback),
86       jsCallback_(jsCallback), onWindowDisplayModeChanged_(onWindowDisplayModeChangedCallBack),
87       onConfigurationUpdated_(onConfigurationUpdatedCallBack),
88       onSaveAbilityState_(onSaveAbilityStateCallBack), onRestoreAbilityState_(onRestoreAbilityStateCallBack),
89       onNewWant_(onNewWantCallBack), onActive_(onActiveCallBack),
90       onInactive_(onInactiveCallBack), onMemoryLevel_(onMemoryLevelCallBack),
91       onStartContinuationCallBack_(onStartContinuationCallBack),
92       onCompleteContinuationCallBack_(onCompleteContinuationCallBack),
93       onRemoteTerminatedCallBack_(onRemoteTerminatedCallBack),
94       onSaveDataCallBack_(onSaveDataCallBack),
95       onRestoreDataCallBack_(onRestoreDataCallBack),
96       manifestParser_(AceType::MakeRefPtr<ManifestParser>()),
97       jsAccessibilityManager_(AccessibilityNodeManager::Create()),
98       mediaQueryInfo_(AceType::MakeRefPtr<MediaQueryInfo>()), taskExecutor_(taskExecutor)
99 {
100 }
101 
~PluginFrontendDelegate()102 PluginFrontendDelegate::~PluginFrontendDelegate()
103 {
104     CHECK_RUN_ON(JS);
105     TAG_LOGI(AceLogTag::ACE_PLUGIN_COMPONENT, "Plugin delegate destroyed");
106 }
107 
GetMinPlatformVersion()108 int32_t PluginFrontendDelegate::GetMinPlatformVersion()
109 {
110     return manifestParser_->GetMinPlatformVersion();
111 }
112 
RunPage(const std::string & url,const std::string & params)113 UIContentErrorCode PluginFrontendDelegate::RunPage(const std::string& url, const std::string& params)
114 {
115     ACE_SCOPED_TRACE("PluginFrontendDelegate::RunPage");
116     std::string jsonContent;
117     if (GetAssetContent(MANIFEST_JSON, jsonContent)) {
118         manifestParser_->Parse(jsonContent);
119         manifestParser_->Printer();
120     } else {
121         LOGE("RunPage parse manifest.json failed");
122         EventReport::SendPageRouterException(PageRouterExcepType::RUN_PAGE_ERR, url);
123     }
124 
125     if (!url.empty()) {
126         mainPagePath_ = manifestParser_->GetRouter()->GetPagePath(url);
127     } else {
128         mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
129     }
130     return LoadPage(GenerateNextPageId(), PageTarget(mainPagePath_), false, params);
131 }
132 
ChangeLocale(const std::string & language,const std::string & countryOrRegion)133 void PluginFrontendDelegate::ChangeLocale(const std::string& language, const std::string& countryOrRegion)
134 {
135     taskExecutor_->PostTask(
136         [language, countryOrRegion]() { AceApplicationInfo::GetInstance().ChangeLocale(language, countryOrRegion); },
137         TaskExecutor::TaskType::PLATFORM, "ArkUIPluginChangeLocale");
138 }
139 
GetI18nData(std::unique_ptr<JsonValue> & json)140 void PluginFrontendDelegate::GetI18nData(std::unique_ptr<JsonValue>& json)
141 {
142     auto data = JsonUtil::CreateArray(true);
143     GetConfigurationCommon(I18N_FOLDER, data);
144     auto i18nData = JsonUtil::Create(true);
145     i18nData->Put("resources", data);
146     json->Put("i18n", i18nData);
147 }
148 
GetResourceConfiguration(std::unique_ptr<JsonValue> & json)149 void PluginFrontendDelegate::GetResourceConfiguration(std::unique_ptr<JsonValue>& json)
150 {
151     auto data = JsonUtil::CreateArray(true);
152     GetConfigurationCommon(RESOURCES_FOLDER, data);
153     json->Put("resourcesConfiguration", data);
154 }
155 
GetConfigurationCommon(const std::string & filePath,std::unique_ptr<JsonValue> & data)156 void PluginFrontendDelegate::GetConfigurationCommon(const std::string& filePath, std::unique_ptr<JsonValue>& data)
157 {
158     std::vector<std::string> files;
159     if (assetManager_) {
160         assetManager_->GetAssetList(filePath, files);
161     }
162 
163     std::vector<std::string> fileNameList;
164     for (const auto& file : files) {
165         if (EndWith(file, FILE_TYPE_JSON) && !StartWith(file, STYLES_FOLDER)) {
166             fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
167         }
168     }
169 
170     std::vector<std::string> priorityFileName;
171     if (filePath.compare(I18N_FOLDER) == 0) {
172         auto localeTag = AceApplicationInfo::GetInstance().GetLocaleTag();
173         priorityFileName = AceResConfig::GetLocaleFallback(localeTag, fileNameList);
174     } else {
175         priorityFileName = AceResConfig::GetResourceFallback(fileNameList);
176     }
177 
178     for (const auto& fileName : priorityFileName) {
179         auto fileFullPath = filePath + fileName + std::string(FILE_TYPE_JSON);
180         std::string content;
181         if (GetAssetContent(fileFullPath, content)) {
182             auto fileData = ParseFileData(content);
183             if (fileData == nullptr) {
184                 LOGW("parse %{private}s.json content failed", filePath.c_str());
185             } else {
186                 data->Put(fileData);
187             }
188         }
189     }
190 }
191 
LoadResourceConfiguration(std::map<std::string,std::string> & mediaResourceFileMap,std::unique_ptr<JsonValue> & currentResourceData)192 void PluginFrontendDelegate::LoadResourceConfiguration(std::map<std::string, std::string>& mediaResourceFileMap,
193     std::unique_ptr<JsonValue>& currentResourceData)
194 {
195     std::vector<std::string> files;
196     if (assetManager_) {
197         assetManager_->GetAssetList(RESOURCES_FOLDER, files);
198     }
199 
200     std::set<std::string> resourceFolderName;
201     for (const auto& file : files) {
202         if (file.find_first_of("/") != std::string::npos) {
203             resourceFolderName.insert(file.substr(0, file.find_first_of("/")));
204         }
205     }
206 
207     auto sortedResourceFolderPath = AceResConfig::GetDeclarativeResourceFallback(resourceFolderName);
208     for (const auto& folderName : sortedResourceFolderPath) {
209         auto fileFullPath = std::string(RESOURCES_FOLDER) + folderName + std::string(I18N_FILE_SUFFIX);
210         std::string content;
211         if (GetAssetContent(fileFullPath, content)) {
212             auto fileData = ParseFileData(content);
213             if (fileData != nullptr) {
214                 currentResourceData->Put(fileData);
215             }
216         }
217     }
218 
219     std::set<std::string> mediaFileName;
220     for (const auto& file : files) {
221         if (file.find_first_of("/") != std::string::npos) {
222             auto mediaPathName = file.substr(file.find_first_of("/"));
223             std::regex mediaPattern(R"(^\/media\/\w*(\.jpg|\.png|\.gif|\.svg|\.webp|\.bmp)$)");
224             std::smatch result;
225             if (std::regex_match(mediaPathName, result, mediaPattern)) {
226                 mediaFileName.insert(mediaPathName.substr(mediaPathName.find_first_of("/")));
227             }
228         }
229     }
230 
231     auto currentResTag = AceResConfig::GetCurrentDeviceResTag();
232     auto currentResolutionTag = currentResTag.substr(currentResTag.find_last_of("-") + 1);
233     for (auto folderName : sortedResourceFolderPath) {
234         for (auto fileName : mediaFileName) {
235             if (mediaResourceFileMap.find(fileName) == mediaResourceFileMap.end()) {
236                 continue;
237             }
238             auto fullFileName = folderName + fileName;
239             if (std::find(files.begin(), files.end(), fullFileName) != files.end()) {
240                 mediaResourceFileMap.emplace(fileName.substr(fileName.find_last_of("/") + 1),
241                     std::string(RESOURCES_FOLDER).append(fullFileName));
242             }
243         }
244         if (mediaResourceFileMap.size() == mediaFileName.size()) {
245             break;
246         }
247     }
248 }
249 
OnJSCallback(const std::string & callbackId,const std::string & data)250 void PluginFrontendDelegate::OnJSCallback(const std::string& callbackId, const std::string& data)
251 {
252     taskExecutor_->PostTask(
253         [weak = AceType::WeakClaim(this), callbackId, args = std::move(data)] {
254             auto delegate = weak.Upgrade();
255             if (delegate) {
256                 delegate->jsCallback_(callbackId, args);
257             }
258         },
259         TaskExecutor::TaskType::JS, "ArkUIPluginHandleJsCallback");
260 }
261 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher) const262 void PluginFrontendDelegate::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) const
263 {
264     taskExecutor_->PostTask([dispatcherCallback = dispatcherCallback_, dispatcher] { dispatcherCallback(dispatcher); },
265         TaskExecutor::TaskType::JS, "ArkUIPluginSetJsMessageDispatcher");
266 }
267 
TransferComponentResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data)268 void PluginFrontendDelegate::TransferComponentResponseData(int32_t callbackId, int32_t code,
269     std::vector<uint8_t>&& data)
270 {
271     auto pipelineContext = pipelineContextHolder_.Get();
272     WeakPtr<PipelineBase> contextWeak(pipelineContext);
273     taskExecutor_->PostTask(
274         [callbackId, data = std::move(data), contextWeak]() mutable {
275             auto context = contextWeak.Upgrade();
276             if (!context) {
277                 LOGE("context is null");
278             } else if (!context->GetMessageBridge()) {
279                 LOGE("messageBridge is null");
280             } else {
281                 context->GetMessageBridge()->HandleCallback(callbackId, std::move(data));
282             }
283         },
284         TaskExecutor::TaskType::UI, "ArkUIPluginTransferComponentResponseData");
285 }
286 
TransferJsResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const287 void PluginFrontendDelegate::TransferJsResponseData(
288     int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
289 {
290     if (groupJsBridge_ && groupJsBridge_->ForwardToWorker(callbackId)) {
291         groupJsBridge_->TriggerModuleJsCallback(callbackId, code, std::move(data));
292         return;
293     }
294 
295     taskExecutor_->PostTask(
296         [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
297             if (groupJsBridge) {
298                 groupJsBridge->TriggerModuleJsCallback(callbackId, code, std::move(data));
299             }
300         },
301         TaskExecutor::TaskType::JS, "ArkUIPluginTransferJsResponseData");
302 }
303 
304 #if defined(PREVIEW)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const305 void PluginFrontendDelegate::TransferJsResponseDataPreview(
306     int32_t callbackId, int32_t code, ResponseData responseData) const
307 {
308     taskExecutor_->PostTask(
309         [callbackId, code, responseData, groupJsBridge = groupJsBridge_]() mutable {
310             if (groupJsBridge) {
311                 groupJsBridge->TriggerModuleJsCallbackPreview(callbackId, code, responseData);
312             }
313         },
314         TaskExecutor::TaskType::JS, "ArkUIPluginTransferJsResponseData");
315 }
316 #endif
317 
TransferJsPluginGetError(int32_t callbackId,int32_t errorCode,std::string && errorMessage) const318 void PluginFrontendDelegate::TransferJsPluginGetError(
319     int32_t callbackId, int32_t errorCode, std::string&& errorMessage) const
320 {
321     taskExecutor_->PostTask(
322         [callbackId, errorCode, errorMessage = std::move(errorMessage), groupJsBridge = groupJsBridge_]() mutable {
323             if (groupJsBridge) {
324                 groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, errorCode, std::move(errorMessage));
325             }
326         },
327         TaskExecutor::TaskType::JS, "ArkUITransferJsPluginGetError");
328 }
329 
TransferJsEventData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const330 void PluginFrontendDelegate::TransferJsEventData(int32_t callbackId, int32_t code,
331     std::vector<uint8_t>&& data) const
332 {
333     taskExecutor_->PostTask(
334         [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
335             if (groupJsBridge) {
336                 groupJsBridge->TriggerEventJsCallback(callbackId, code, std::move(data));
337             }
338         },
339         TaskExecutor::TaskType::JS, "ArkUIPluginTransferJsEventData");
340 }
341 
LoadPluginJsCode(std::string && jsCode) const342 void PluginFrontendDelegate::LoadPluginJsCode(std::string&& jsCode) const
343 {
344     taskExecutor_->PostTask(
345         [jsCode = std::move(jsCode), groupJsBridge = groupJsBridge_]() mutable {
346             if (groupJsBridge) {
347                 groupJsBridge->LoadPluginJsCode(std::move(jsCode));
348             }
349         },
350         TaskExecutor::TaskType::JS, "ArkUILoadPluginJsCode");
351 }
352 
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen) const353 void PluginFrontendDelegate::LoadPluginJsByteCode(
354     std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen) const
355 {
356     if (groupJsBridge_ == nullptr) {
357         LOGE("groupJsBridge_ is nullptr");
358         return;
359     }
360     taskExecutor_->PostTask(
361         [jsCode = std::move(jsCode), jsCodeLen = std::move(jsCodeLen), groupJsBridge = groupJsBridge_]() mutable {
362             groupJsBridge->LoadPluginJsByteCode(std::move(jsCode), std::move(jsCodeLen));
363         },
364         TaskExecutor::TaskType::JS, "ArkUILoadPluginJsByteCode");
365 }
366 
OnPageBackPress()367 bool PluginFrontendDelegate::OnPageBackPress()
368 {
369     auto result = false;
370     taskExecutor_->PostSyncTask(
371         [weak = AceType::WeakClaim(this), &result] {
372             auto delegate = weak.Upgrade();
373             CHECK_NULL_VOID(delegate);
374             auto pageId = delegate->GetRunningPageId();
375             auto page = delegate->GetPage(pageId);
376             if (page) {
377                 result = page->FireDeclarativeOnBackPressCallback();
378             }
379         },
380         TaskExecutor::TaskType::JS, "ArkUIPluginPageBackPress");
381     return result;
382 }
383 
NotifyAppStorage(const WeakPtr<Framework::JsEngine> & jsEngineWeak,const std::string & key,const std::string & value)384 void PluginFrontendDelegate::NotifyAppStorage(const WeakPtr<Framework::JsEngine>& jsEngineWeak,
385     const std::string& key, const std::string& value)
386 {
387     taskExecutor_->PostTask(
388         [jsEngineWeak, key, value] {
389             auto jsEngine = jsEngineWeak.Upgrade();
390             CHECK_NULL_VOID(jsEngine);
391             jsEngine->NotifyAppStorage(key, value);
392         },
393         TaskExecutor::TaskType::JS, "ArkUIPluginNotifyAppStorage");
394 }
395 
OnSuspended()396 void PluginFrontendDelegate::OnSuspended()
397 {
398     FireAsyncEvent("_root", std::string("\"viewsuspended\",null,null"), std::string(""));
399 }
400 
OnBackGround()401 void PluginFrontendDelegate::OnBackGround()
402 {
403     taskExecutor_->PostTask(
404         [weak = AceType::WeakClaim(this)] {
405             auto delegate = weak.Upgrade();
406             CHECK_NULL_VOID(delegate);
407             delegate->OnPageHide();
408         },
409         TaskExecutor::TaskType::JS, "ArkUIPluginPageHide");
410 }
411 
OnForeground()412 void PluginFrontendDelegate::OnForeground()
413 {
414     taskExecutor_->PostTask(
415         [weak = AceType::WeakClaim(this)] {
416             auto delegate = weak.Upgrade();
417             CHECK_NULL_VOID(delegate);
418             delegate->OnPageShow();
419         },
420         TaskExecutor::TaskType::JS, "ArkUIPluginPageShow");
421 }
422 
OnConfigurationUpdated(const std::string & data)423 void PluginFrontendDelegate::OnConfigurationUpdated(const std::string& data)
424 {
425     taskExecutor_->PostSyncTask(
426         [onConfigurationUpdated = onConfigurationUpdated_, data] {
427             onConfigurationUpdated(data);
428         },
429         TaskExecutor::TaskType::JS, "ArkUIPluginConfigurationUpdated");
430 }
431 
OnStartContinuation()432 bool PluginFrontendDelegate::OnStartContinuation()
433 {
434     bool ret = false;
435     taskExecutor_->PostSyncTask(
436         [weak = AceType::WeakClaim(this), &ret] {
437             auto delegate = weak.Upgrade();
438             if (delegate && delegate->onStartContinuationCallBack_) {
439                 ret = delegate->onStartContinuationCallBack_();
440             }
441         },
442         TaskExecutor::TaskType::JS, "ArkUIPluginStartContinuation");
443     return ret;
444 }
445 
OnCompleteContinuation(int32_t code)446 void PluginFrontendDelegate::OnCompleteContinuation(int32_t code)
447 {
448     taskExecutor_->PostSyncTask(
449         [weak = AceType::WeakClaim(this), code] {
450             auto delegate = weak.Upgrade();
451             if (delegate && delegate->onCompleteContinuationCallBack_) {
452                 delegate->onCompleteContinuationCallBack_(code);
453             }
454         },
455         TaskExecutor::TaskType::JS, "ArkUIPluginCompleteContinuation");
456 }
457 
OnRemoteTerminated()458 void PluginFrontendDelegate::OnRemoteTerminated()
459 {
460     taskExecutor_->PostSyncTask(
461         [weak = AceType::WeakClaim(this)] {
462             auto delegate = weak.Upgrade();
463             if (delegate && delegate->onRemoteTerminatedCallBack_) {
464                 delegate->onRemoteTerminatedCallBack_();
465             }
466         },
467         TaskExecutor::TaskType::JS, "ArkUIPluginRemoteTerminated");
468 }
469 
OnSaveData(std::string & data)470 void PluginFrontendDelegate::OnSaveData(std::string& data)
471 {
472     std::string savedData;
473     taskExecutor_->PostSyncTask(
474         [weak = AceType::WeakClaim(this), &savedData] {
475             auto delegate = weak.Upgrade();
476             if (delegate && delegate->onSaveDataCallBack_) {
477                 delegate->onSaveDataCallBack_(savedData);
478             }
479         },
480         TaskExecutor::TaskType::JS, "ArkUIPluginSaveData");
481     std::string pageUri = GetRunningPageUrl();
482     data = std::string("{\"url\":\"").append(pageUri).append("\",\"__remoteData\":").append(savedData).append("}");
483 }
484 
OnRestoreData(const std::string & data)485 bool PluginFrontendDelegate::OnRestoreData(const std::string& data)
486 {
487     bool ret = false;
488     taskExecutor_->PostSyncTask(
489         [weak = AceType::WeakClaim(this), &data, &ret] {
490             auto delegate = weak.Upgrade();
491             if (delegate && delegate->onRestoreDataCallBack_) {
492                 ret = delegate->onRestoreDataCallBack_(data);
493             }
494         },
495         TaskExecutor::TaskType::JS, "ArkUIPluginRestoreData");
496     return ret;
497 }
498 
OnMemoryLevel(const int32_t level)499 void PluginFrontendDelegate::OnMemoryLevel(const int32_t level)
500 {
501     taskExecutor_->PostTask(
502         [onMemoryLevel = onMemoryLevel_, level]() {
503             if (onMemoryLevel) {
504                 onMemoryLevel(level);
505             }
506         },
507         TaskExecutor::TaskType::JS, "ArkUIPluginMemoryLevel");
508 }
509 
GetPluginsUsed(std::string & data)510 void PluginFrontendDelegate::GetPluginsUsed(std::string& data)
511 {
512     if (!GetAssetContentImpl(assetManager_, "module_collection.txt", data)) {
513         LOGW("read failed, will load all the system plugin");
514         data = "All";
515     }
516 }
517 
OnActive()518 void PluginFrontendDelegate::OnActive()
519 {
520     taskExecutor_->PostTask(
521         [onActive = onActive_]() {
522             onActive();
523         },
524         TaskExecutor::TaskType::JS, "ArkUIPluginActive");
525 }
526 
OnInactive()527 void PluginFrontendDelegate::OnInactive()
528 {
529     taskExecutor_->PostTask(
530         [onInactive = onInactive_]() {
531             onInactive();
532         },
533         TaskExecutor::TaskType::JS, "ArkUIPluginInactive");
534 }
535 
OnNewRequest(const std::string & data)536 void PluginFrontendDelegate::OnNewRequest(const std::string& data)
537 {
538     FireSyncEvent("_root", std::string("\"onNewRequest\","), data);
539 }
540 
CallPopPage()541 void PluginFrontendDelegate::CallPopPage()
542 {
543     PopPage();
544 }
545 
ResetStagingPage()546 void PluginFrontendDelegate::ResetStagingPage()
547 {
548     taskExecutor_->PostTask([resetStagingPage = resetStagingPage_] { resetStagingPage(); },
549         TaskExecutor::TaskType::JS, "ArkUIPluginResetStagingPage");
550 }
551 
OnApplicationDestroy(const std::string & packageName)552 void PluginFrontendDelegate::OnApplicationDestroy(const std::string& packageName)
553 {
554     taskExecutor_->PostSyncTask(
555         [destroyApplication = destroyApplication_, packageName] { destroyApplication(packageName); },
556         TaskExecutor::TaskType::JS, "ArkUIPluginApplicationDestroy");
557 }
558 
UpdateApplicationState(const std::string & packageName,Frontend::State state)559 void PluginFrontendDelegate::UpdateApplicationState(const std::string& packageName, Frontend::State state)
560 {
561     taskExecutor_->PostTask(
562         [updateApplicationState = updateApplicationState_, packageName, state] {
563             updateApplicationState(packageName, state);
564         },
565         TaskExecutor::TaskType::JS, "ArkUIPluginUpdateApplicationState");
566 }
567 
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)568 void PluginFrontendDelegate::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
569 {
570     taskExecutor_->PostTask(
571         [onWindowDisplayModeChanged = onWindowDisplayModeChanged_, isShownInMultiWindow, data] {
572             onWindowDisplayModeChanged(isShownInMultiWindow, data);
573         },
574         TaskExecutor::TaskType::JS, "ArkUIPluginWindowDisplayModeChanged");
575 }
576 
OnSaveAbilityState(std::string & data)577 void PluginFrontendDelegate::OnSaveAbilityState(std::string& data)
578 {
579     taskExecutor_->PostSyncTask(
580         [onSaveAbilityState = onSaveAbilityState_, &data] {
581             onSaveAbilityState(data);
582         },
583         TaskExecutor::TaskType::JS, "ArkUIPluginSaveAbilityState");
584 }
585 
OnRestoreAbilityState(const std::string & data)586 void PluginFrontendDelegate::OnRestoreAbilityState(const std::string& data)
587 {
588     taskExecutor_->PostTask(
589         [onRestoreAbilityState = onRestoreAbilityState_, data] {
590             onRestoreAbilityState(data);
591         },
592         TaskExecutor::TaskType::JS, "ArkUIPluginRestoreAbilityState");
593 }
594 
OnNewWant(const std::string & data)595 void PluginFrontendDelegate::OnNewWant(const std::string& data)
596 {
597     taskExecutor_->PostTask(
598         [onNewWant = onNewWant_, data] {
599             onNewWant(data);
600         },
601         TaskExecutor::TaskType::JS, "ArkUIPluginNewWant");
602 }
603 
FireAsyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)604 void PluginFrontendDelegate::FireAsyncEvent(
605     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
606 {
607     std::string args = param;
608     args.append(",null").append(",null"); // callback and dom changes
609     if (!jsonArgs.empty()) {
610         args.append(",").append(jsonArgs); // method args
611     }
612     taskExecutor_->PostTask(
613         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
614             auto delegate = weak.Upgrade();
615             if (delegate) {
616                 delegate->asyncEvent_(eventId, args);
617             }
618         },
619         TaskExecutor::TaskType::JS, "ArkUIPluginFireAsyncEvent");
620 }
621 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)622 bool PluginFrontendDelegate::FireSyncEvent(
623     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
624 {
625     std::string resultStr;
626     FireSyncEvent(eventId, param, jsonArgs, resultStr);
627     return (resultStr == "true");
628 }
629 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs,std::string & result)630 void PluginFrontendDelegate::FireSyncEvent(
631     const std::string& eventId, const std::string& param, const std::string& jsonArgs, std::string& result)
632 {
633     int32_t callbackId = callbackCnt_++;
634     std::string args = param;
635     args.append("{\"_callbackId\":\"").append(std::to_string(callbackId)).append("\"}").append(",null");
636     if (!jsonArgs.empty()) {
637         args.append(",").append(jsonArgs); // method args
638     }
639     taskExecutor_->PostSyncTask(
640         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
641             auto delegate = weak.Upgrade();
642             if (delegate) {
643                 delegate->syncEvent_(eventId, args);
644             }
645         },
646         TaskExecutor::TaskType::JS, "ArkUIPluginFireSyncEvent");
647 
648     result = jsCallBackResult_[callbackId];
649     jsCallBackResult_.erase(callbackId);
650 }
651 
FireAccessibilityEvent(const AccessibilityEvent & accessibilityEvent)652 void PluginFrontendDelegate::FireAccessibilityEvent(const AccessibilityEvent& accessibilityEvent)
653 {
654     jsAccessibilityManager_->SendAccessibilityAsyncEvent(accessibilityEvent);
655 }
656 
InitializeAccessibilityCallback()657 void PluginFrontendDelegate::InitializeAccessibilityCallback()
658 {
659     jsAccessibilityManager_->InitializeCallback();
660 }
661 
662 // Start FrontendDelegate overrides.
Push(const std::string & uri,const std::string & params)663 void PluginFrontendDelegate::Push(const std::string& uri, const std::string& params)
664 {
665     Push(PageTarget(uri), params);
666 }
667 
Replace(const std::string & uri,const std::string & params)668 void PluginFrontendDelegate::Replace(const std::string& uri, const std::string& params)
669 {
670     Replace(PageTarget(uri), params);
671 }
672 
Back(const std::string & uri,const std::string & params)673 void PluginFrontendDelegate::Back(const std::string& uri, const std::string& params)
674 {
675     BackWithTarget(PageTarget(uri), params);
676 }
677 
Push(const PageTarget & target,const std::string & params)678 void PluginFrontendDelegate::Push(const PageTarget& target, const std::string& params)
679 {
680     if (target.url.empty()) {
681         LOGE("router.Push uri is empty");
682         return;
683     }
684     if (isRouteStackFull_) {
685         LOGE("the router stack has reached its max size, you can't push any more pages.");
686         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, target.url);
687         return;
688     }
689 
690     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
691     if (!pagePath.empty()) {
692         LoadPage(GenerateNextPageId(), PageTarget(pagePath, target.container), false, params);
693     } else {
694         LOGW("[Engine Log] this uri not support in route push.");
695     }
696 }
697 
Replace(const PageTarget & target,const std::string & params)698 void PluginFrontendDelegate::Replace(const PageTarget& target, const std::string& params)
699 {
700     if (target.url.empty()) {
701         LOGE("router.Replace uri is empty");
702         return;
703     }
704 
705     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
706     if (!pagePath.empty()) {
707         LoadReplacePage(GenerateNextPageId(), PageTarget(pagePath, target.container), params);
708     } else {
709         LOGW("[Engine Log] this uri not support in route replace.");
710     }
711 }
712 
PostponePageTransition()713 void PluginFrontendDelegate::PostponePageTransition()
714 {
715     taskExecutor_->PostTask(
716         [weak = AceType::WeakClaim(this)] {
717           auto delegate = weak.Upgrade();
718           CHECK_NULL_VOID(delegate);
719           auto pipelineContext = delegate->pipelineContextHolder_.Get();
720           pipelineContext->PostponePageTransition();
721         },
722         TaskExecutor::TaskType::UI, "ArkUIPluginPostponePageTransition");
723 }
724 
LaunchPageTransition()725 void PluginFrontendDelegate::LaunchPageTransition()
726 {
727     taskExecutor_->PostTask(
728         [weak = AceType::WeakClaim(this)] {
729           auto delegate = weak.Upgrade();
730           CHECK_NULL_VOID(delegate);
731           auto pipelineContext = delegate->pipelineContextHolder_.Get();
732           pipelineContext->LaunchPageTransition();
733         },
734         TaskExecutor::TaskType::UI, "ArkUIPluginLaunchPageTransition");
735 }
736 
BackWithTarget(const PageTarget & target,const std::string & params)737 void PluginFrontendDelegate::BackWithTarget(const PageTarget& target, const std::string& params)
738 {
739     if (target.url.empty()) {
740         {
741             std::lock_guard<std::mutex> lock(mutex_);
742             if (pageRouteStack_.size() > 1) {
743                 pageId_ = pageRouteStack_[pageRouteStack_.size() - MIN_ROUT_COUNT].pageId;
744             }
745             if (!params.empty()) {
746                 pageParamMap_[pageId_] = params;
747             }
748         }
749         PopPage();
750     } else {
751         std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
752         if (!pagePath.empty()) {
753             pageId_ = GetPageIdByUrl(target.url);
754             if (!params.empty()) {
755                 std::lock_guard<std::mutex> lock(mutex_);
756                 pageParamMap_[pageId_] = params;
757             }
758             PopToPage(pagePath);
759         } else {
760             LOGW("[Engine Log] this uri not support in route Back.");
761         }
762     }
763 }
764 
Clear()765 void PluginFrontendDelegate::Clear()
766 {
767     ClearInvisiblePages();
768 }
769 
GetStackSize() const770 int32_t PluginFrontendDelegate::GetStackSize() const
771 {
772     std::lock_guard<std::mutex> lock(mutex_);
773     return static_cast<int32_t>(pageRouteStack_.size());
774 }
775 
GetState(int32_t & index,std::string & name,std::string & path)776 void PluginFrontendDelegate::GetState(int32_t& index, std::string& name, std::string& path)
777 {
778     std::string url;
779     {
780         std::lock_guard<std::mutex> lock(mutex_);
781         if (pageRouteStack_.empty()) {
782             return;
783         }
784         index = static_cast<int32_t>(pageRouteStack_.size());
785         url = pageRouteStack_.back().url;
786     }
787     auto pos = url.rfind(".js");
788     if (pos == url.length() - JS_HEADER_OFFSET) {
789         url = url.substr(0, pos);
790     }
791     pos = url.rfind("/");
792     if (pos != std::string::npos) {
793         name = url.substr(pos + 1);
794         path = url.substr(0, pos + 1);
795     }
796 }
797 
GetComponentsCount()798 size_t PluginFrontendDelegate::GetComponentsCount()
799 {
800     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
801     CHECK_NULL_RETURN(pipelineContext, 0);
802     const auto& pageElement = pipelineContext->GetLastPage();
803     if (pageElement) {
804         return pageElement->GetComponentsCount();
805     }
806     return 0;
807 }
808 
GetParams()809 std::string PluginFrontendDelegate::GetParams()
810 {
811     auto iter = pageParamMap_.find(pageId_);
812     if (iter != pageParamMap_.end()) {
813         return iter->second;
814     } else {
815         return "";
816     }
817 }
818 
TriggerPageUpdate(int32_t pageId,bool directExecute)819 void PluginFrontendDelegate::TriggerPageUpdate(int32_t pageId, bool directExecute)
820 {
821     auto page = GetPage(pageId);
822     CHECK_NULL_VOID(page);
823 
824     auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
825     ACE_DCHECK(jsPage);
826 
827     // Pop all JS command and execute them in UI thread.
828     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
829     jsPage->PopAllCommands(*jsCommands);
830 
831     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
832     CHECK_NULL_VOID(pipelineContext);
833     WeakPtr<Framework::JsAcePage> jsPageWeak(jsPage);
834     WeakPtr<PipelineContext> contextWeak(pipelineContext);
835     auto updateTask = [jsPageWeak, contextWeak, jsCommands] {
836         ACE_SCOPED_TRACE("FlushUpdateCommands");
837         auto jsPage = jsPageWeak.Upgrade();
838         auto context = contextWeak.Upgrade();
839         if (!jsPage || !context) {
840             LOGE("Page update failed. page or context is null.");
841             EventReport::SendPageRouterException(PageRouterExcepType::UPDATE_PAGE_ERR);
842             return;
843         }
844         // Flush all JS commands.
845         for (const auto& command : *jsCommands) {
846             command->Execute(jsPage);
847         }
848         if (jsPage->GetDomDocument()) {
849             jsPage->GetDomDocument()->HandleComponentPostBinding();
850         }
851         auto accessibilityManager = context->GetAccessibilityManager();
852         if (accessibilityManager) {
853             accessibilityManager->HandleComponentPostBinding();
854         }
855 
856         jsPage->ClearShowCommand();
857         std::vector<NodeId> dirtyNodes;
858         jsPage->PopAllDirtyNodes(dirtyNodes);
859         for (auto nodeId : dirtyNodes) {
860             auto patchComponent = jsPage->BuildPagePatch(nodeId);
861             if (patchComponent) {
862                 context->ScheduleUpdate(patchComponent);
863             }
864         }
865     };
866 
867     taskExecutor_->PostTask(
868         [updateTask, pipelineContext, directExecute]() {
869             pipelineContext->AddPageUpdateTask(std::move(updateTask), directExecute);
870         },
871         TaskExecutor::TaskType::UI, "ArkUIPluginAddPageUpdateTask");
872 }
873 
PostJsTask(std::function<void ()> && task,const std::string & name)874 void PluginFrontendDelegate::PostJsTask(std::function<void()>&& task, const std::string& name)
875 {
876     taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS, name);
877 }
878 
GetAppID() const879 const std::string& PluginFrontendDelegate::GetAppID() const
880 {
881     return manifestParser_->GetAppInfo()->GetAppID();
882 }
883 
GetAppName() const884 const std::string& PluginFrontendDelegate::GetAppName() const
885 {
886     return manifestParser_->GetAppInfo()->GetAppName();
887 }
888 
GetVersionName() const889 const std::string& PluginFrontendDelegate::GetVersionName() const
890 {
891     return manifestParser_->GetAppInfo()->GetVersionName();
892 }
893 
GetVersionCode() const894 int32_t PluginFrontendDelegate::GetVersionCode() const
895 {
896     return manifestParser_->GetAppInfo()->GetVersionCode();
897 }
898 
MeasureText(MeasureContext context)899 double PluginFrontendDelegate::MeasureText(MeasureContext context)
900 {
901     if (context.isFontSizeUseDefaultUnit && context.fontSize.has_value() &&
902         !AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
903         context.fontSize = Dimension(context.fontSize->Value(), DimensionUnit::VP);
904     }
905     return MeasureUtil::MeasureText(context);
906 }
907 
MeasureTextSize(MeasureContext context)908 Size PluginFrontendDelegate::MeasureTextSize(MeasureContext context)
909 {
910     if (context.isFontSizeUseDefaultUnit && context.fontSize.has_value() &&
911         !AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
912         context.fontSize = Dimension(context.fontSize->Value(), DimensionUnit::VP);
913     }
914     return MeasureUtil::MeasureTextSize(context);
915 }
916 
ShowToast(const NG::ToastInfo & toastInfo,std::function<void (int32_t)> && callback)917 void PluginFrontendDelegate::ShowToast(const NG::ToastInfo& toastInfo, std::function<void(int32_t)>&& callback)
918 {
919     NG::ToastInfo updatedToastInfo = toastInfo;
920     updatedToastInfo.duration = std::clamp(toastInfo.duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
921     updatedToastInfo.isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
922     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
923     taskExecutor_->PostTask(
924         [updatedToastInfo, context = pipelineContext] {
925             ToastComponent::GetInstance().Show(context, updatedToastInfo.message, updatedToastInfo.duration,
926                 updatedToastInfo.bottom, updatedToastInfo.isRightToLeft);
927         },
928         TaskExecutor::TaskType::UI, "ArkUIPluginShowToast");
929 }
930 
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)931 void PluginFrontendDelegate::ShowDialog(const std::string& title, const std::string& message,
932     const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
933     const std::set<std::string>& callbacks)
934 {
935     std::unordered_map<std::string, EventMarker> callbackMarkers;
936     if (callbacks.find(COMMON_SUCCESS) != callbacks.end()) {
937         auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
938         BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
939             successEventMarker, [callback, taskExecutor = taskExecutor_](int32_t successType) {
940                 taskExecutor->PostTask(
941                     [callback, successType]() { callback(0, successType); },
942                     TaskExecutor::TaskType::JS, "ArkUIPluginShowDialogSuccess");
943             });
944         callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
945     }
946 
947     if (callbacks.find(COMMON_CANCEL) != callbacks.end()) {
948         auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
949         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
950             cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
951                 taskExecutor->PostTask(
952                     [callback]() { callback(1, 0); }, TaskExecutor::TaskType::JS, "ArkUIPluginShowDialogCancel");
953             });
954         callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
955     }
956 
957     if (callbacks.find(COMMON_COMPLETE) != callbacks.end()) {
958         auto completeEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
959         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
960             completeEventMarker, [callback, taskExecutor = taskExecutor_] {
961                 taskExecutor->PostTask(
962                     [callback]() { callback(MIN_ROUT_COUNT, 0); },
963                     TaskExecutor::TaskType::JS, "ArkUIPluginShowDialogComplete");
964             });
965         callbackMarkers.emplace(COMMON_COMPLETE, completeEventMarker);
966     }
967 
968     DialogProperties dialogProperties = {
969         .title = title,
970         .content = message,
971         .autoCancel = autoCancel,
972         .buttons = buttons,
973         .callbacks = std::move(callbackMarkers),
974     };
975     auto context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
976     if (context) {
977         context->ShowDialog(dialogProperties, AceApplicationInfo::GetInstance().IsRightToLeft());
978     }
979 }
980 
GetBoundingRectData(NodeId nodeId)981 Rect PluginFrontendDelegate::GetBoundingRectData(NodeId nodeId)
982 {
983     Rect rect;
984     auto task = [context = pipelineContextHolder_.Get(), nodeId, &rect]() {
985         context->GetBoundingRectData(nodeId, rect);
986     };
987     PostSyncTaskToPage(task, "ArkUIPluginGetBoundingRectData");
988     return rect;
989 }
990 
GetInspector(NodeId nodeId)991 std::string PluginFrontendDelegate::GetInspector(NodeId nodeId)
992 {
993     std::string attrs;
994     auto task = [weak = WeakClaim(AceType::RawPtr(jsAccessibilityManager_)), nodeId, &attrs]() {
995         auto accessibilityNodeManager = weak.Upgrade();
996         if (accessibilityNodeManager) {
997             attrs = accessibilityNodeManager->GetInspectorNodeById(nodeId);
998         }
999     };
1000     PostSyncTaskToPage(task, "ArkUIPluginGetInspectorNode");
1001     return attrs;
1002 }
1003 
SetCallBackResult(const std::string & callBackId,const std::string & result)1004 void PluginFrontendDelegate::SetCallBackResult(const std::string& callBackId, const std::string& result)
1005 {
1006     jsCallBackResult_.try_emplace(StringToInt(callBackId), result);
1007 }
1008 
WaitTimer(const std::string & callbackId,const std::string & delay,bool isInterval,bool isFirst)1009 void PluginFrontendDelegate::WaitTimer(
1010     const std::string& callbackId, const std::string& delay, bool isInterval, bool isFirst)
1011 {
1012     if (!isFirst) {
1013         auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1014         // If not find the callbackId in map, means this timer already was removed,
1015         // no need create a new cancelableTimer again.
1016         if (timeoutTaskIter == timeoutTaskMap_.end()) {
1017             return;
1018         }
1019     }
1020 
1021     int32_t delayTime = StringToInt(delay);
1022     // CancelableCallback class can only be executed once.
1023     CancelableCallback<void()> cancelableTimer;
1024     cancelableTimer.Reset([callbackId, delay, isInterval, call = timer_] { call(callbackId, delay, isInterval); });
1025     auto result = timeoutTaskMap_.try_emplace(callbackId, cancelableTimer);
1026     if (!result.second) {
1027         result.first->second = cancelableTimer;
1028     }
1029     taskExecutor_->PostDelayedTask(cancelableTimer, TaskExecutor::TaskType::JS, delayTime, "ArkUIPluginWaitTimer");
1030 }
1031 
ClearTimer(const std::string & callbackId)1032 void PluginFrontendDelegate::ClearTimer(const std::string& callbackId)
1033 {
1034     auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1035     if (timeoutTaskIter != timeoutTaskMap_.end()) {
1036         timeoutTaskIter->second.Cancel();
1037         timeoutTaskMap_.erase(timeoutTaskIter);
1038     } else {
1039         LOGW("ClearTimer callbackId not found");
1040     }
1041 }
1042 
PostSyncTaskToPage(std::function<void ()> && task,const std::string & name)1043 void PluginFrontendDelegate::PostSyncTaskToPage(std::function<void()>&& task, const std::string& name)
1044 {
1045     pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
1046     taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::UI, name);
1047 }
1048 
AddTaskObserver(std::function<void ()> && task)1049 void PluginFrontendDelegate::AddTaskObserver(std::function<void()>&& task)
1050 {
1051     taskExecutor_->AddTaskObserver(std::move(task));
1052 }
1053 
RemoveTaskObserver()1054 void PluginFrontendDelegate::RemoveTaskObserver()
1055 {
1056     taskExecutor_->RemoveTaskObserver();
1057 }
1058 
GetAssetContent(const std::string & url,std::string & content)1059 bool PluginFrontendDelegate::GetAssetContent(const std::string& url, std::string& content)
1060 {
1061     return GetAssetContentImpl(assetManager_, url, content);
1062 }
1063 
GetAssetContent(const std::string & url,std::vector<uint8_t> & content)1064 bool PluginFrontendDelegate::GetAssetContent(const std::string& url, std::vector<uint8_t>& content)
1065 {
1066     return GetAssetContentImpl(assetManager_, url, content);
1067 }
1068 
GetAssetPath(const std::string & url)1069 std::string PluginFrontendDelegate::GetAssetPath(const std::string& url)
1070 {
1071     return GetAssetPathImpl(assetManager_, url);
1072 }
1073 
LoadPage(int32_t pageId,const PageTarget & target,bool isMainPage,const std::string & params)1074 UIContentErrorCode PluginFrontendDelegate::LoadPage(
1075     int32_t pageId, const PageTarget& target, bool isMainPage, const std::string& params)
1076 {
1077     {
1078         std::lock_guard<std::mutex> lock(mutex_);
1079         pageId_ = pageId;
1080         pageParamMap_[pageId] = params;
1081     }
1082     auto url = target.url;
1083     if (pageId == INVALID_PAGE_ID) {
1084         LOGE("PluginFrontendDelegate, invalid page id");
1085         EventReport::SendPageRouterException(PageRouterExcepType::LOAD_PAGE_ERR, url);
1086         return UIContentErrorCode::INVALID_PAGE_ID;
1087     }
1088     if (isStagingPageExist_) {
1089         LOGE("PluginFrontendDelegate, load page failed, waiting for current page loading finish.");
1090         RecyclePageId(pageId);
1091         return UIContentErrorCode::STAGING_PAGE_EXIST;
1092     }
1093     isStagingPageExist_ = true;
1094     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1095     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1096     page->SetPageParams(params);
1097     page->SetPluginComponentJsonData(params);
1098     page->SetFlushCallback([weak = AceType::WeakClaim(this), isMainPage](const RefPtr<JsAcePage>& acePage) {
1099         auto delegate = weak.Upgrade();
1100         if (delegate && acePage) {
1101             delegate->FlushPageCommand(acePage, acePage->GetUrl(), isMainPage);
1102         }
1103     });
1104     LoadJS(page, url, isMainPage);
1105     return UIContentErrorCode::NO_ERRORS;
1106 }
1107 
LoadJS(const RefPtr<Framework::JsAcePage> & page,const std::string & url,bool isMainPage)1108 void PluginFrontendDelegate::LoadJS(
1109     const RefPtr<Framework::JsAcePage>& page, const std::string& url, bool isMainPage)
1110 {
1111     taskExecutor_->PostTask(
1112         [weak = AceType::WeakClaim(this), page, url, isMainPage] {
1113             auto delegate = weak.Upgrade();
1114             CHECK_NULL_VOID(delegate);
1115             delegate->loadJs_(url, page, isMainPage);
1116             page->FlushCommands();
1117             // just make sure the pipelineContext is created.
1118             auto pipeline = delegate->pipelineContextHolder_.Get();
1119             pipeline->SetMinPlatformVersion(delegate->GetMinPlatformVersion());
1120             delegate->taskExecutor_->PostTask(
1121                 [weak, page] {
1122                     auto delegate = weak.Upgrade();
1123                     if (delegate && delegate->pipelineContextHolder_.Get()) {
1124                         auto context = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1125                         if (context) {
1126                             context->FlushFocus();
1127                         }
1128                     }
1129                     if (page->GetDomDocument()) {
1130                         page->GetDomDocument()->HandlePageLoadFinish();
1131                     }
1132                 },
1133                 TaskExecutor::TaskType::UI, "ArkUIPluginPageLoadFinish");
1134         },
1135         TaskExecutor::TaskType::JS, "ArkUIPluginLoadJsPage");
1136 }
1137 
OnSurfaceChanged()1138 void PluginFrontendDelegate::OnSurfaceChanged()
1139 {
1140     if (mediaQueryInfo_->GetIsInit()) {
1141         mediaQueryInfo_->SetIsInit(false);
1142     }
1143     mediaQueryInfo_->EnsureListenerIdValid();
1144     OnMediaQueryUpdate();
1145 }
1146 
OnMediaQueryUpdate(bool isSynchronous)1147 void PluginFrontendDelegate::OnMediaQueryUpdate(bool isSynchronous)
1148 {
1149     if (mediaQueryInfo_->GetIsInit()) {
1150         return;
1151     }
1152 
1153     taskExecutor_->PostTask(
1154         [weak = AceType::WeakClaim(this)] {
1155             auto delegate = weak.Upgrade();
1156             CHECK_NULL_VOID(delegate);
1157             const auto& info = delegate->mediaQueryInfo_->GetMediaQueryInfo();
1158             // request css mediaquery
1159             std::string param("\"viewsizechanged\",");
1160             param.append(info);
1161             delegate->asyncEvent_("_root", param);
1162 
1163             // request js mediaquery
1164             const auto& listenerId = delegate->mediaQueryInfo_->GetListenerId();
1165             delegate->mediaQueryCallback_(listenerId, info);
1166             delegate->mediaQueryInfo_->ResetListenerId();
1167         },
1168         TaskExecutor::TaskType::JS, "ArkUIPluginMediaQueryUpdate");
1169 }
1170 
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1171 void PluginFrontendDelegate::OnPageReady(
1172     const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1173 {
1174     // Pop all JS command and execute them in UI thread.
1175     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1176     page->PopAllCommands(*jsCommands);
1177 
1178     auto pipelineContext = pipelineContextHolder_.Get();
1179     page->SetPipelineContext(pipelineContext);
1180     taskExecutor_->PostTask(
1181         [weak = AceType::WeakClaim(this), page, url, jsCommands, isMainPage] {
1182             auto delegate = weak.Upgrade();
1183             CHECK_NULL_VOID(delegate);
1184             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1185             CHECK_NULL_VOID(pipelineContext);
1186             // Flush all JS commands.
1187             for (const auto& command : *jsCommands) {
1188                 command->Execute(page);
1189             }
1190             // Just clear all dirty nodes.
1191             page->ClearAllDirtyNodes();
1192             if (page->GetDomDocument()) {
1193                 page->GetDomDocument()->HandleComponentPostBinding();
1194             }
1195             if (pipelineContext->GetAccessibilityManager()) {
1196                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1197             }
1198             if (pipelineContext->CanPushPage()) {
1199                 if (!isMainPage) {
1200                     delegate->OnPageHide();
1201                 }
1202                 delegate->OnPrePageChange(page);
1203                 pipelineContext->PushPage(page->BuildPage(url), page->GetStageElement());
1204                 delegate->OnPushPageSuccess(page, url);
1205                 delegate->SetCurrentPage(page->GetPageId());
1206                 delegate->OnMediaQueryUpdate();
1207             } else {
1208                 // This page has been loaded but become useless now, the corresponding js instance
1209                 // must be destroyed to avoid memory leak.
1210                 delegate->OnPageDestroy(page->GetPageId());
1211                 delegate->ResetStagingPage();
1212             }
1213             delegate->isStagingPageExist_ = false;
1214             if (isMainPage) {
1215                 delegate->OnPageShow();
1216             }
1217         },
1218         TaskExecutor::TaskType::UI, "ArkUIPluginPageReady");
1219 }
1220 
OnPrePageChange(const RefPtr<JsAcePage> & page)1221 void PluginFrontendDelegate::OnPrePageChange(const RefPtr<JsAcePage>& page)
1222 {
1223     if (page && page->GetDomDocument() && jsAccessibilityManager_) {
1224         jsAccessibilityManager_->SetRootNodeId(page->GetDomDocument()->GetRootNodeId());
1225     }
1226 }
1227 
FlushPageCommand(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1228 void PluginFrontendDelegate::FlushPageCommand(
1229     const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1230 {
1231     CHECK_NULL_VOID(page);
1232     if (page->FragmentCount() == 1) {
1233         OnPageReady(page, url, isMainPage);
1234     } else {
1235         TriggerPageUpdate(page->GetPageId());
1236     }
1237 }
1238 
AddPageLocked(const RefPtr<JsAcePage> & page)1239 void PluginFrontendDelegate::AddPageLocked(const RefPtr<JsAcePage>& page)
1240 {
1241     auto result = pageMap_.try_emplace(page->GetPageId(), page);
1242     if (!result.second) {
1243         LOGW("the page has already in the map");
1244     }
1245 }
1246 
SetCurrentPage(int32_t pageId)1247 void PluginFrontendDelegate::SetCurrentPage(int32_t pageId)
1248 {
1249     auto page = GetPage(pageId);
1250     if (page != nullptr) {
1251         jsAccessibilityManager_->SetVersion(AccessibilityVersion::JS_DECLARATIVE_VERSION);
1252         jsAccessibilityManager_->SetRunningPage(page);
1253         taskExecutor_->PostTask([updatePage = updatePage_, page] { updatePage(page); },
1254             TaskExecutor::TaskType::JS, "ArkUIPluginSetCurrentPage");
1255     } else {
1256         LOGE("PluginFrontendDelegate SetCurrentPage page is null.");
1257     }
1258 }
1259 
OnPushPageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1260 void PluginFrontendDelegate::OnPushPageSuccess(
1261     const RefPtr<JsAcePage>& page, const std::string& url)
1262 {
1263     std::lock_guard<std::mutex> lock(mutex_);
1264     AddPageLocked(page);
1265     pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url, false, {}, {} });
1266     if (Container::IsCurrentUseNewPipeline()) {
1267         FireDeclarativeOnUpdateWithValueParamsCallback(page->GetPluginComponentJsonData());
1268     } else {
1269         page->FireDeclarativeOnUpdateWithValueParamsCallback(page->GetPluginComponentJsonData());
1270     }
1271     if (pageRouteStack_.size() >= MAX_ROUTER_STACK) {
1272         isRouteStackFull_ = true;
1273         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, page->GetUrl());
1274     }
1275 }
1276 
OnPopToPageSuccess(const std::string & url)1277 void PluginFrontendDelegate::OnPopToPageSuccess(const std::string& url)
1278 {
1279     std::lock_guard<std::mutex> lock(mutex_);
1280     while (!pageRouteStack_.empty()) {
1281         if (pageRouteStack_.back().url == url) {
1282             break;
1283         }
1284         OnPageDestroy(pageRouteStack_.back().pageId);
1285         pageMap_.erase(pageRouteStack_.back().pageId);
1286         pageParamMap_.erase(pageRouteStack_.back().pageId);
1287         pageRouteStack_.pop_back();
1288     }
1289 
1290     if (isRouteStackFull_) {
1291         isRouteStackFull_ = false;
1292     }
1293 }
1294 
PopToPage(const std::string & url)1295 void PluginFrontendDelegate::PopToPage(const std::string& url)
1296 {
1297     taskExecutor_->PostTask(
1298         [weak = AceType::WeakClaim(this), url] {
1299             auto delegate = weak.Upgrade();
1300             CHECK_NULL_VOID(delegate);
1301             auto pageId = delegate->GetPageIdByUrl(url);
1302             if (pageId == INVALID_PAGE_ID) {
1303                 return;
1304             }
1305             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1306             CHECK_NULL_VOID(pipelineContext);
1307             if (!pipelineContext->CanPopPage()) {
1308                 delegate->ResetStagingPage();
1309                 return;
1310             }
1311             delegate->OnPageHide();
1312             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1313             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1314                 [weak, url, pageId](
1315                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1316                     auto delegate = weak.Upgrade();
1317                     if (delegate) {
1318                         delegate->PopToPageTransitionListener(event, url, pageId);
1319                     }
1320                 });
1321             pipelineContext->PopToPage(pageId);
1322         },
1323         TaskExecutor::TaskType::UI, "ArkUIPluginPopToPage");
1324 }
1325 
PopToPageTransitionListener(const TransitionEvent & event,const std::string & url,int32_t pageId)1326 void PluginFrontendDelegate::PopToPageTransitionListener(
1327     const TransitionEvent& event, const std::string& url, int32_t pageId)
1328 {
1329     if (event == TransitionEvent::POP_END) {
1330         OnPopToPageSuccess(url);
1331         SetCurrentPage(pageId);
1332         OnPageShow();
1333         OnMediaQueryUpdate();
1334     }
1335 }
1336 
OnPopPageSuccess()1337 int32_t PluginFrontendDelegate::OnPopPageSuccess()
1338 {
1339     std::lock_guard<std::mutex> lock(mutex_);
1340     pageMap_.erase(pageRouteStack_.back().pageId);
1341     pageParamMap_.erase(pageRouteStack_.back().pageId);
1342     pageRouteStack_.pop_back();
1343     if (isRouteStackFull_) {
1344         isRouteStackFull_ = false;
1345     }
1346     if (!pageRouteStack_.empty()) {
1347         return pageRouteStack_.back().pageId;
1348     }
1349     return INVALID_PAGE_ID;
1350 }
1351 
PopPage()1352 void PluginFrontendDelegate::PopPage()
1353 {
1354     taskExecutor_->PostTask(
1355         [weak = AceType::WeakClaim(this)] {
1356             auto delegate = weak.Upgrade();
1357             CHECK_NULL_VOID(delegate);
1358             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1359             CHECK_NULL_VOID(pipelineContext);
1360             if (delegate->GetStackSize() == 1) {
1361                 if (delegate->disallowPopLastPage_) {
1362                     LOGW("Not allow back because this is the last page!");
1363                     return;
1364                 }
1365                 delegate->OnPageHide();
1366                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1367                 delegate->OnPopPageSuccess();
1368                 pipelineContext->Finish();
1369                 return;
1370             }
1371             if (!pipelineContext->CanPopPage()) {
1372                 delegate->ResetStagingPage();
1373                 return;
1374             }
1375             delegate->OnPageHide();
1376             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1377             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1378                 [weak, destroyPageId = delegate->GetRunningPageId()](
1379                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1380                     auto delegate = weak.Upgrade();
1381                     if (delegate) {
1382                         delegate->PopPageTransitionListener(event, destroyPageId);
1383                     }
1384                 });
1385             pipelineContext->PopPage();
1386         },
1387         TaskExecutor::TaskType::UI, "ArkUIPluginPopPage");
1388 }
1389 
PopPageTransitionListener(const TransitionEvent & event,int32_t destroyPageId)1390 void PluginFrontendDelegate::PopPageTransitionListener(
1391     const TransitionEvent& event, int32_t destroyPageId)
1392 {
1393     if (event == TransitionEvent::POP_END) {
1394         OnPageDestroy(destroyPageId);
1395         auto pageId = OnPopPageSuccess();
1396         SetCurrentPage(pageId);
1397         OnPageShow();
1398         OnMediaQueryUpdate();
1399     }
1400 }
1401 
OnClearInvisiblePagesSuccess()1402 int32_t PluginFrontendDelegate::OnClearInvisiblePagesSuccess()
1403 {
1404     std::lock_guard<std::mutex> lock(mutex_);
1405     PageInfo pageInfo = std::move(pageRouteStack_.back());
1406     pageRouteStack_.pop_back();
1407     for (const auto& info : pageRouteStack_) {
1408         OnPageDestroy(info.pageId);
1409         pageMap_.erase(info.pageId);
1410         pageParamMap_.erase(info.pageId);
1411     }
1412     pageRouteStack_.clear();
1413     int32_t resPageId = pageInfo.pageId;
1414     pageRouteStack_.emplace_back(std::move(pageInfo));
1415     if (isRouteStackFull_) {
1416         isRouteStackFull_ = false;
1417     }
1418     return resPageId;
1419 }
1420 
ClearInvisiblePages()1421 void PluginFrontendDelegate::ClearInvisiblePages()
1422 {
1423     taskExecutor_->PostTask(
1424         [weak = AceType::WeakClaim(this)] {
1425             auto delegate = weak.Upgrade();
1426             CHECK_NULL_VOID(delegate);
1427             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1428             CHECK_NULL_VOID(pipelineContext);
1429             if (pipelineContext->ClearInvisiblePages()) {
1430                 auto pageId = delegate->OnClearInvisiblePagesSuccess();
1431                 delegate->SetCurrentPage(pageId);
1432             }
1433         },
1434         TaskExecutor::TaskType::UI, "ArkUIPluginClearInvisiblePages");
1435 }
1436 
OnReplacePageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1437 void PluginFrontendDelegate::OnReplacePageSuccess(
1438     const RefPtr<JsAcePage>& page, const std::string& url)
1439 {
1440     CHECK_NULL_VOID(page);
1441     std::lock_guard<std::mutex> lock(mutex_);
1442     AddPageLocked(page);
1443     if (!pageRouteStack_.empty()) {
1444         pageMap_.erase(pageRouteStack_.back().pageId);
1445         pageParamMap_.erase(pageRouteStack_.back().pageId);
1446         pageRouteStack_.pop_back();
1447     }
1448     pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url, false, {}, {} });
1449 }
1450 
ReplacePage(const RefPtr<JsAcePage> & page,const std::string & url)1451 void PluginFrontendDelegate::ReplacePage(
1452     const RefPtr<JsAcePage>& page, const std::string& url)
1453 {
1454     // Pop all JS command and execute them in UI thread.
1455     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1456     page->PopAllCommands(*jsCommands);
1457 
1458     auto pipelineContext = pipelineContextHolder_.Get();
1459     page->SetPipelineContext(pipelineContext);
1460     taskExecutor_->PostTask(
1461         [weak = AceType::WeakClaim(this), page, url, jsCommands] {
1462             auto delegate = weak.Upgrade();
1463             CHECK_NULL_VOID(delegate);
1464             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1465             CHECK_NULL_VOID(pipelineContext);
1466             // Flush all JS commands.
1467             for (const auto& command : *jsCommands) {
1468                 command->Execute(page);
1469             }
1470             // Just clear all dirty nodes.
1471             page->ClearAllDirtyNodes();
1472             page->GetDomDocument()->HandleComponentPostBinding();
1473             if (pipelineContext->GetAccessibilityManager()) {
1474                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1475             }
1476             if (pipelineContext->CanReplacePage()) {
1477                 delegate->OnPageHide();
1478                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1479                 delegate->OnPrePageChange(page);
1480                 pipelineContext->ReplacePage(page->BuildPage(url), page->GetStageElement());
1481                 delegate->OnReplacePageSuccess(page, url);
1482                 delegate->SetCurrentPage(page->GetPageId());
1483                 delegate->OnMediaQueryUpdate();
1484             } else {
1485                 // This page has been loaded but become useless now, the corresponding js instance
1486                 // must be destroyed to avoid memory leak.
1487                 delegate->OnPageDestroy(page->GetPageId());
1488                 delegate->ResetStagingPage();
1489             }
1490             delegate->isStagingPageExist_ = false;
1491         },
1492         TaskExecutor::TaskType::UI, "ArkUIPluginReplacePage");
1493 }
1494 
LoadReplacePage(int32_t pageId,const PageTarget & target,const std::string & params)1495 void PluginFrontendDelegate::LoadReplacePage(int32_t pageId, const PageTarget& target, const std::string& params)
1496 {
1497     {
1498         std::lock_guard<std::mutex> lock(mutex_);
1499         pageId_ = pageId;
1500         pageParamMap_[pageId] = params;
1501     }
1502     auto url = target.url;
1503     if (pageId == INVALID_PAGE_ID) {
1504         LOGE("PluginFrontendDelegate, invalid page id");
1505         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1506         return;
1507     }
1508     if (isStagingPageExist_) {
1509         LOGE("PluginFrontendDelegate, replace page failed, waiting for current page loading finish.");
1510         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1511         return;
1512     }
1513     isStagingPageExist_ = true;
1514     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1515     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1516     page->SetPageParams(params);
1517     taskExecutor_->PostTask(
1518         [page, url, weak = AceType::WeakClaim(this)] {
1519             auto delegate = weak.Upgrade();
1520             if (delegate) {
1521                 delegate->loadJs_(url, page, false);
1522                 delegate->ReplacePage(page, url);
1523             }
1524         },
1525         TaskExecutor::TaskType::JS, "ArkUIPluginLoadReplacePage");
1526 }
1527 
SetColorMode(ColorMode colorMode)1528 void PluginFrontendDelegate::SetColorMode(ColorMode colorMode)
1529 {
1530     OnMediaQueryUpdate();
1531 }
1532 
RebuildAllPages()1533 void PluginFrontendDelegate::RebuildAllPages()
1534 {
1535     std::unordered_map<int32_t, RefPtr<JsAcePage>> pages;
1536     {
1537         std::lock_guard<std::mutex> lock(mutex_);
1538         pages.insert(pageMap_.begin(), pageMap_.end());
1539     }
1540     for (const auto& [pageId, page] : pages) {
1541         page->FireDeclarativeOnPageRefreshCallback();
1542         TriggerPageUpdate(page->GetPageId(), true);
1543     }
1544 }
1545 
OnPageShow()1546 void PluginFrontendDelegate::OnPageShow()
1547 {
1548     auto pageId = GetRunningPageId();
1549     auto page = GetPage(pageId);
1550     if (page) {
1551         page->FireDeclarativeOnPageAppearCallback();
1552     }
1553     FireAsyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
1554 }
1555 
OnPageHide()1556 void PluginFrontendDelegate::OnPageHide()
1557 {
1558     auto pageId = GetRunningPageId();
1559     auto page = GetPage(pageId);
1560     if (page) {
1561         page->FireDeclarativeOnPageDisAppearCallback();
1562     }
1563     FireAsyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
1564 }
1565 
OnPageDestroy(int32_t pageId)1566 void PluginFrontendDelegate::OnPageDestroy(int32_t pageId)
1567 {
1568     taskExecutor_->PostTask(
1569         [weak = AceType::WeakClaim(this), pageId] {
1570             auto delegate = weak.Upgrade();
1571             if (delegate) {
1572                 delegate->destroyPage_(pageId);
1573                 delegate->RecyclePageId(pageId);
1574             }
1575         },
1576         TaskExecutor::TaskType::JS, "ArkUIPluginPageDestroy");
1577 }
1578 
GetRunningPageId() const1579 int32_t PluginFrontendDelegate::GetRunningPageId() const
1580 {
1581     std::lock_guard<std::mutex> lock(mutex_);
1582     if (pageRouteStack_.empty()) {
1583         return INVALID_PAGE_ID;
1584     }
1585     return pageRouteStack_.back().pageId;
1586 }
1587 
GetRunningPageUrl() const1588 std::string PluginFrontendDelegate::GetRunningPageUrl() const
1589 {
1590     std::lock_guard<std::mutex> lock(mutex_);
1591     if (pageRouteStack_.empty()) {
1592         return std::string();
1593     }
1594     const auto& pageUrl = pageRouteStack_.back().url;
1595     auto pos = pageUrl.rfind(".js");
1596     if (pos == pageUrl.length() - JS_HEADER_OFFSET) {
1597         return pageUrl.substr(0, pos);
1598     }
1599     return pageUrl;
1600 }
1601 
GetPageIdByUrl(const std::string & url)1602 int32_t PluginFrontendDelegate::GetPageIdByUrl(const std::string& url)
1603 {
1604     std::lock_guard<std::mutex> lock(mutex_);
1605     auto pageIter = std::find_if(std::rbegin(pageRouteStack_), std::rend(pageRouteStack_),
1606         [&url](const PageInfo& pageRoute) { return url == pageRoute.url; });
1607     if (pageIter != std::rend(pageRouteStack_)) {
1608         LOGW("GetPageIdByUrl pageId=%{private}d url=%{private}s", pageIter->pageId, url.c_str());
1609         return pageIter->pageId;
1610     }
1611     return INVALID_PAGE_ID;
1612 }
1613 
GetPage(int32_t pageId) const1614 RefPtr<JsAcePage> PluginFrontendDelegate::GetPage(int32_t pageId) const
1615 {
1616     std::lock_guard<std::mutex> lock(mutex_);
1617     auto itPage = pageMap_.find(pageId);
1618     if (itPage == pageMap_.end()) {
1619         LOGE("the page is not in the map");
1620         return nullptr;
1621     }
1622     return itPage->second;
1623 }
1624 
RegisterFont(const std::string & familyName,const std::string & familySrc,const std::string & bundleName,const std::string & moduleName)1625 void PluginFrontendDelegate::RegisterFont(const std::string& familyName, const std::string& familySrc,
1626     const std::string& bundleName, const std::string& moduleName)
1627 {
1628     pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc, bundleName, moduleName);
1629 }
1630 
GetSystemFontList(std::vector<std::string> & fontList)1631 void PluginFrontendDelegate::GetSystemFontList(std::vector<std::string>& fontList)
1632 {
1633     pipelineContextHolder_.Get()->GetSystemFontList(fontList);
1634 }
1635 
GetSystemFont(const std::string & fontName,FontInfo & fontInfo)1636 bool PluginFrontendDelegate::GetSystemFont(const std::string& fontName, FontInfo& fontInfo)
1637 {
1638     return pipelineContextHolder_.Get()->GetSystemFont(fontName, fontInfo);
1639 }
1640 
HandleImage(const std::string & src,std::function<void (bool,int32_t,int32_t)> && callback)1641 void PluginFrontendDelegate::HandleImage(
1642     const std::string& src, std::function<void(bool, int32_t, int32_t)>&& callback)
1643 {
1644     if (src.empty() || !callback) {
1645         return;
1646     }
1647     auto loadCallback = [jsCallback = std::move(callback), taskExecutor = taskExecutor_](
1648                             bool success, int32_t width, int32_t height) {
1649         taskExecutor->PostTask(
1650             [callback = std::move(jsCallback), success, width, height] { callback(success, width, height); },
1651             TaskExecutor::TaskType::JS, "ArkUIPluginHandleImage");
1652     };
1653     pipelineContextHolder_.Get()->TryLoadImageInfo(src, std::move(loadCallback));
1654 }
1655 
PushJsCallbackToRenderNode(NodeId id,double ratio,std::function<void (bool,double)> && callback)1656 void PluginFrontendDelegate::PushJsCallbackToRenderNode(NodeId id, double ratio,
1657     std::function<void(bool, double)>&& callback)
1658 {
1659     LOGW("Not implement in declarative frontend.");
1660 }
1661 
RequestAnimationFrame(const std::string & callbackId)1662 void PluginFrontendDelegate::RequestAnimationFrame(const std::string& callbackId)
1663 {
1664     CancelableCallback<void()> cancelableTask;
1665     cancelableTask.Reset([callbackId, call = requestAnimationCallback_, weak = AceType::WeakClaim(this)] {
1666         auto delegate = weak.Upgrade();
1667         if (delegate && call) {
1668             call(callbackId, delegate->GetSystemRealTime());
1669         }
1670     });
1671     animationFrameTaskMap_.try_emplace(callbackId, cancelableTask);
1672     animationFrameTaskIds_.emplace(callbackId);
1673 }
1674 
GetSystemRealTime()1675 uint64_t PluginFrontendDelegate::GetSystemRealTime()
1676 {
1677     struct timespec ts;
1678     clock_gettime(CLOCK_REALTIME, &ts);
1679     return ts.tv_sec * TO_MILLI + ts.tv_nsec / NANO_TO_MILLI;
1680 }
1681 
CancelAnimationFrame(const std::string & callbackId)1682 void PluginFrontendDelegate::CancelAnimationFrame(const std::string& callbackId)
1683 {
1684     auto animationTaskIter = animationFrameTaskMap_.find(callbackId);
1685     if (animationTaskIter != animationFrameTaskMap_.end()) {
1686         animationTaskIter->second.Cancel();
1687         animationFrameTaskMap_.erase(animationTaskIter);
1688     } else {
1689         LOGW("cancelAnimationFrame callbackId not found");
1690     }
1691 }
1692 
FlushAnimationTasks()1693 void PluginFrontendDelegate::FlushAnimationTasks()
1694 {
1695     while (!animationFrameTaskIds_.empty()) {
1696         const auto& callbackId = animationFrameTaskIds_.front();
1697         if (!callbackId.empty()) {
1698             auto taskIter = animationFrameTaskMap_.find(callbackId);
1699             if (taskIter != animationFrameTaskMap_.end()) {
1700                 taskExecutor_->PostTask(taskIter->second, TaskExecutor::TaskType::JS, "ArkUIPluginFlushAnimationTask");
1701             }
1702         }
1703         animationFrameTaskIds_.pop();
1704     }
1705 }
1706 
GetAnimationJsTask()1707 SingleTaskExecutor PluginFrontendDelegate::GetAnimationJsTask()
1708 {
1709     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::JS);
1710 }
1711 
GetUiTask()1712 SingleTaskExecutor PluginFrontendDelegate::GetUiTask()
1713 {
1714     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::UI);
1715 }
1716 
AttachPipelineContext(const RefPtr<PipelineBase> & context)1717 void PluginFrontendDelegate::AttachPipelineContext(const RefPtr<PipelineBase>& context)
1718 {
1719     CHECK_NULL_VOID(context);
1720     context->SetOnPageShow([weak = AceType::WeakClaim(this)] {
1721         auto delegate = weak.Upgrade();
1722         if (delegate) {
1723             delegate->OnPageShow();
1724         }
1725     });
1726     context->SetAnimationCallback([weak = AceType::WeakClaim(this)] {
1727         auto delegate = weak.Upgrade();
1728         if (delegate) {
1729             delegate->FlushAnimationTasks();
1730         }
1731     });
1732     pipelineContextHolder_.Attach(context);
1733     jsAccessibilityManager_->SetPipelineContext(context);
1734     jsAccessibilityManager_->InitializeCallback();
1735 }
1736 
GetPipelineContext()1737 RefPtr<PipelineBase> PluginFrontendDelegate::GetPipelineContext()
1738 {
1739     return pipelineContextHolder_.Get();
1740 }
1741 
UpdatePlugin(const std::string & content)1742 void PluginFrontendDelegate::UpdatePlugin(const std::string& content)
1743 {
1744     auto pageId = GetRunningPageId();
1745     auto page = GetPage(pageId);
1746     if (Container::IsCurrentUseNewPipeline()) {
1747         FireDeclarativeOnUpdateWithValueParamsCallback(content);
1748         return;
1749     }
1750     if (page) {
1751         page->FireDeclarativeOnUpdateWithValueParamsCallback(content);
1752     }
1753 }
1754 } // namespace OHOS::Ace::Framework
1755