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