• 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 <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/utils.h"
27 #include "base/utils/measure_util.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 void 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     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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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_NOLOG(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);
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_NOLOG(jsEngine);
407             jsEngine->NotifyAppStorage(key, value);
408         },
409         TaskExecutor::TaskType::JS);
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_NOLOG(delegate);
423             delegate->OnPageHide();
424         },
425         TaskExecutor::TaskType::JS);
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_NOLOG(delegate);
434             delegate->OnPageShow();
435         },
436         TaskExecutor::TaskType::JS);
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);
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);
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);
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);
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);
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);
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);
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);
541 }
542 
OnInactive()543 void PluginFrontendDelegate::OnInactive()
544 {
545     taskExecutor_->PostTask(
546         [onInactive = onInactive_]() {
547             onInactive();
548         },
549         TaskExecutor::TaskType::JS);
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(); }, TaskExecutor::TaskType::JS);
565 }
566 
OnApplicationDestroy(const std::string & packageName)567 void PluginFrontendDelegate::OnApplicationDestroy(const std::string& packageName)
568 {
569     taskExecutor_->PostSyncTask(
570         [destroyApplication = destroyApplication_, packageName] { destroyApplication(packageName); },
571         TaskExecutor::TaskType::JS);
572 }
573 
UpdateApplicationState(const std::string & packageName,Frontend::State state)574 void PluginFrontendDelegate::UpdateApplicationState(const std::string& packageName, Frontend::State state)
575 {
576     taskExecutor_->PostTask(
577         [updateApplicationState = updateApplicationState_, packageName, state] {
578             updateApplicationState(packageName, state);
579         },
580         TaskExecutor::TaskType::JS);
581 }
582 
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)583 void PluginFrontendDelegate::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
584 {
585     taskExecutor_->PostTask(
586         [onWindowDisplayModeChanged = onWindowDisplayModeChanged_, isShownInMultiWindow, data] {
587             onWindowDisplayModeChanged(isShownInMultiWindow, data);
588         },
589         TaskExecutor::TaskType::JS);
590 }
591 
OnSaveAbilityState(std::string & data)592 void PluginFrontendDelegate::OnSaveAbilityState(std::string& data)
593 {
594     taskExecutor_->PostSyncTask(
595         [onSaveAbilityState = onSaveAbilityState_, &data] {
596             onSaveAbilityState(data);
597         },
598         TaskExecutor::TaskType::JS);
599 }
600 
OnRestoreAbilityState(const std::string & data)601 void PluginFrontendDelegate::OnRestoreAbilityState(const std::string& data)
602 {
603     taskExecutor_->PostTask(
604         [onRestoreAbilityState = onRestoreAbilityState_, data] {
605             onRestoreAbilityState(data);
606         },
607         TaskExecutor::TaskType::JS);
608 }
609 
OnNewWant(const std::string & data)610 void PluginFrontendDelegate::OnNewWant(const std::string& data)
611 {
612     taskExecutor_->PostTask(
613         [onNewWant = onNewWant_, data] {
614             onNewWant(data);
615         },
616         TaskExecutor::TaskType::JS);
617 }
618 
FireAsyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)619 void PluginFrontendDelegate::FireAsyncEvent(
620     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
621 {
622     std::string args = param;
623     args.append(",null").append(",null"); // callback and dom changes
624     if (!jsonArgs.empty()) {
625         args.append(",").append(jsonArgs); // method args
626     }
627     taskExecutor_->PostTask(
628         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
629             auto delegate = weak.Upgrade();
630             if (delegate) {
631                 delegate->asyncEvent_(eventId, args);
632             }
633         },
634         TaskExecutor::TaskType::JS);
635 }
636 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)637 bool PluginFrontendDelegate::FireSyncEvent(
638     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
639 {
640     std::string resultStr;
641     FireSyncEvent(eventId, param, jsonArgs, resultStr);
642     return (resultStr == "true");
643 }
644 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs,std::string & result)645 void PluginFrontendDelegate::FireSyncEvent(
646     const std::string& eventId, const std::string& param, const std::string& jsonArgs, std::string& result)
647 {
648     int32_t callbackId = callbackCnt_++;
649     std::string args = param;
650     args.append("{\"_callbackId\":\"").append(std::to_string(callbackId)).append("\"}").append(",null");
651     if (!jsonArgs.empty()) {
652         args.append(",").append(jsonArgs); // method args
653     }
654     taskExecutor_->PostSyncTask(
655         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
656             auto delegate = weak.Upgrade();
657             if (delegate) {
658                 delegate->syncEvent_(eventId, args);
659             }
660         },
661         TaskExecutor::TaskType::JS);
662 
663     result = jsCallBackResult_[callbackId];
664     jsCallBackResult_.erase(callbackId);
665 }
666 
FireAccessibilityEvent(const AccessibilityEvent & accessibilityEvent)667 void PluginFrontendDelegate::FireAccessibilityEvent(const AccessibilityEvent& accessibilityEvent)
668 {
669     jsAccessibilityManager_->SendAccessibilityAsyncEvent(accessibilityEvent);
670 }
671 
InitializeAccessibilityCallback()672 void PluginFrontendDelegate::InitializeAccessibilityCallback()
673 {
674     jsAccessibilityManager_->InitializeCallback();
675 }
676 
677 // Start FrontendDelegate overrides.
Push(const std::string & uri,const std::string & params)678 void PluginFrontendDelegate::Push(const std::string& uri, const std::string& params)
679 {
680     Push(PageTarget(uri), params);
681 }
682 
Replace(const std::string & uri,const std::string & params)683 void PluginFrontendDelegate::Replace(const std::string& uri, const std::string& params)
684 {
685     Replace(PageTarget(uri), params);
686 }
687 
Back(const std::string & uri,const std::string & params)688 void PluginFrontendDelegate::Back(const std::string& uri, const std::string& params)
689 {
690     BackWithTarget(PageTarget(uri), params);
691 }
692 
Push(const PageTarget & target,const std::string & params)693 void PluginFrontendDelegate::Push(const PageTarget& target, const std::string& params)
694 {
695     if (target.url.empty()) {
696         LOGE("router.Push uri is empty");
697         return;
698     }
699     if (isRouteStackFull_) {
700         LOGE("the router stack has reached its max size, you can't push any more pages.");
701         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, target.url);
702         return;
703     }
704 
705     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
706     if (!pagePath.empty()) {
707         LoadPage(GenerateNextPageId(), PageTarget(pagePath, target.container), false, params);
708     } else {
709         LOGW("[Engine Log] this uri not support in route push.");
710     }
711 }
712 
Replace(const PageTarget & target,const std::string & params)713 void PluginFrontendDelegate::Replace(const PageTarget& target, const std::string& params)
714 {
715     if (target.url.empty()) {
716         LOGE("router.Replace uri is empty");
717         return;
718     }
719 
720     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
721     if (!pagePath.empty()) {
722         LoadReplacePage(GenerateNextPageId(), PageTarget(pagePath, target.container), params);
723     } else {
724         LOGW("[Engine Log] this uri not support in route replace.");
725     }
726 }
727 
PostponePageTransition()728 void PluginFrontendDelegate::PostponePageTransition()
729 {
730     taskExecutor_->PostTask(
731         [weak = AceType::WeakClaim(this)] {
732           auto delegate = weak.Upgrade();
733           CHECK_NULL_VOID_NOLOG(delegate);
734           auto pipelineContext = delegate->pipelineContextHolder_.Get();
735           pipelineContext->PostponePageTransition();
736         },
737         TaskExecutor::TaskType::UI);
738 }
739 
LaunchPageTransition()740 void PluginFrontendDelegate::LaunchPageTransition()
741 {
742     taskExecutor_->PostTask(
743         [weak = AceType::WeakClaim(this)] {
744           auto delegate = weak.Upgrade();
745           CHECK_NULL_VOID_NOLOG(delegate);
746           auto pipelineContext = delegate->pipelineContextHolder_.Get();
747           pipelineContext->LaunchPageTransition();
748         },
749         TaskExecutor::TaskType::UI);
750 }
751 
BackWithTarget(const PageTarget & target,const std::string & params)752 void PluginFrontendDelegate::BackWithTarget(const PageTarget& target, const std::string& params)
753 {
754     if (target.url.empty()) {
755         {
756             std::lock_guard<std::mutex> lock(mutex_);
757             if (pageRouteStack_.size() > 1) {
758                 pageId_ = pageRouteStack_[pageRouteStack_.size() - MIN_ROUT_COUNT].pageId;
759             }
760             if (!params.empty()) {
761                 pageParamMap_[pageId_] = params;
762             }
763         }
764         PopPage();
765     } else {
766         std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
767         if (!pagePath.empty()) {
768             pageId_ = GetPageIdByUrl(target.url);
769             if (!params.empty()) {
770                 std::lock_guard<std::mutex> lock(mutex_);
771                 pageParamMap_[pageId_] = params;
772             }
773             PopToPage(pagePath);
774         } else {
775             LOGW("[Engine Log] this uri not support in route Back.");
776         }
777     }
778 }
779 
Clear()780 void PluginFrontendDelegate::Clear()
781 {
782     ClearInvisiblePages();
783 }
784 
GetStackSize() const785 int32_t PluginFrontendDelegate::GetStackSize() const
786 {
787     std::lock_guard<std::mutex> lock(mutex_);
788     return static_cast<int32_t>(pageRouteStack_.size());
789 }
790 
GetState(int32_t & index,std::string & name,std::string & path)791 void PluginFrontendDelegate::GetState(int32_t& index, std::string& name, std::string& path)
792 {
793     std::string url;
794     {
795         std::lock_guard<std::mutex> lock(mutex_);
796         if (pageRouteStack_.empty()) {
797             return;
798         }
799         index = static_cast<int32_t>(pageRouteStack_.size());
800         url = pageRouteStack_.back().url;
801     }
802     auto pos = url.rfind(".js");
803     if (pos == url.length() - JS_HEADER_OFFSET) {
804         url = url.substr(0, pos);
805     }
806     pos = url.rfind("/");
807     if (pos != std::string::npos) {
808         name = url.substr(pos + 1);
809         path = url.substr(0, pos + 1);
810     }
811 }
812 
GetComponentsCount()813 size_t PluginFrontendDelegate::GetComponentsCount()
814 {
815     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
816     CHECK_NULL_RETURN(pipelineContext, 0);
817     const auto& pageElement = pipelineContext->GetLastPage();
818     if (pageElement) {
819         return pageElement->GetComponentsCount();
820     }
821     return 0;
822 }
823 
GetParams()824 std::string PluginFrontendDelegate::GetParams()
825 {
826     if (pageParamMap_.find(pageId_) != pageParamMap_.end()) {
827         return pageParamMap_.find(pageId_)->second;
828     } else {
829         return "";
830     }
831 }
832 
TriggerPageUpdate(int32_t pageId,bool directExecute)833 void PluginFrontendDelegate::TriggerPageUpdate(int32_t pageId, bool directExecute)
834 {
835     auto page = GetPage(pageId);
836     CHECK_NULL_VOID_NOLOG(page);
837 
838     auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
839     ACE_DCHECK(jsPage);
840 
841     // Pop all JS command and execute them in UI thread.
842     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
843     jsPage->PopAllCommands(*jsCommands);
844 
845     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
846     CHECK_NULL_VOID(pipelineContext);
847     WeakPtr<Framework::JsAcePage> jsPageWeak(jsPage);
848     WeakPtr<PipelineContext> contextWeak(pipelineContext);
849     auto updateTask = [jsPageWeak, contextWeak, jsCommands] {
850         ACE_SCOPED_TRACE("FlushUpdateCommands");
851         auto jsPage = jsPageWeak.Upgrade();
852         auto context = contextWeak.Upgrade();
853         if (!jsPage || !context) {
854             LOGE("Page update failed. page or context is null.");
855             EventReport::SendPageRouterException(PageRouterExcepType::UPDATE_PAGE_ERR);
856             return;
857         }
858         // Flush all JS commands.
859         for (const auto& command : *jsCommands) {
860             command->Execute(jsPage);
861         }
862         if (jsPage->GetDomDocument()) {
863             jsPage->GetDomDocument()->HandleComponentPostBinding();
864         }
865         auto accessibilityManager = context->GetAccessibilityManager();
866         if (accessibilityManager) {
867             accessibilityManager->HandleComponentPostBinding();
868         }
869 
870         jsPage->ClearShowCommand();
871         std::vector<NodeId> dirtyNodes;
872         jsPage->PopAllDirtyNodes(dirtyNodes);
873         for (auto nodeId : dirtyNodes) {
874             auto patchComponent = jsPage->BuildPagePatch(nodeId);
875             if (patchComponent) {
876                 context->ScheduleUpdate(patchComponent);
877             }
878         }
879     };
880 
881     taskExecutor_->PostTask(
882         [updateTask, pipelineContext, directExecute]() {
883             pipelineContext->AddPageUpdateTask(std::move(updateTask), directExecute);
884         },
885         TaskExecutor::TaskType::UI);
886 }
887 
PostJsTask(std::function<void ()> && task)888 void PluginFrontendDelegate::PostJsTask(std::function<void()>&& task)
889 {
890     taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS);
891 }
892 
RemoveVisibleChangeNode(NodeId id)893 void PluginFrontendDelegate::RemoveVisibleChangeNode(NodeId id)
894 {
895     LOGW("RemoveVisibleChangeNode: Not implemented yet.");
896 }
897 
GetAppID() const898 const std::string& PluginFrontendDelegate::GetAppID() const
899 {
900     return manifestParser_->GetAppInfo()->GetAppID();
901 }
902 
GetAppName() const903 const std::string& PluginFrontendDelegate::GetAppName() const
904 {
905     return manifestParser_->GetAppInfo()->GetAppName();
906 }
907 
GetVersionName() const908 const std::string& PluginFrontendDelegate::GetVersionName() const
909 {
910     return manifestParser_->GetAppInfo()->GetVersionName();
911 }
912 
GetVersionCode() const913 int32_t PluginFrontendDelegate::GetVersionCode() const
914 {
915     return manifestParser_->GetAppInfo()->GetVersionCode();
916 }
917 
MeasureText(const MeasureContext & context)918 double PluginFrontendDelegate::MeasureText(const MeasureContext& context)
919 {
920     return MeasureUtil::MeasureText(context);
921 }
922 
MeasureTextSize(const MeasureContext & context)923 Size PluginFrontendDelegate::MeasureTextSize(const MeasureContext& context)
924 {
925     return MeasureUtil::MeasureTextSize(context);
926 }
927 
ShowToast(const std::string & message,int32_t duration,const std::string & bottom)928 void PluginFrontendDelegate::ShowToast(const std::string& message, int32_t duration, const std::string& bottom)
929 {
930     int32_t durationTime = std::clamp(duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
931     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
932     bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
933     taskExecutor_->PostTask(
934         [durationTime, message, bottom, isRightToLeft, context = pipelineContext] {
935             ToastComponent::GetInstance().Show(context, message, durationTime, bottom, isRightToLeft);
936         },
937         TaskExecutor::TaskType::UI);
938 }
939 
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)940 void PluginFrontendDelegate::ShowDialog(const std::string& title, const std::string& message,
941     const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
942     const std::set<std::string>& callbacks)
943 {
944     std::unordered_map<std::string, EventMarker> callbackMarkers;
945     if (callbacks.find(COMMON_SUCCESS) != callbacks.end()) {
946         auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
947         BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
948             successEventMarker, [callback, taskExecutor = taskExecutor_](int32_t successType) {
949                 taskExecutor->PostTask(
950                     [callback, successType]() { callback(0, successType); }, TaskExecutor::TaskType::JS);
951             });
952         callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
953     }
954 
955     if (callbacks.find(COMMON_CANCEL) != callbacks.end()) {
956         auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
957         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
958             cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
959                 taskExecutor->PostTask([callback]() { callback(1, 0); }, TaskExecutor::TaskType::JS);
960             });
961         callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
962     }
963 
964     if (callbacks.find(COMMON_COMPLETE) != callbacks.end()) {
965         auto completeEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
966         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
967             completeEventMarker, [callback, taskExecutor = taskExecutor_] {
968                 taskExecutor->PostTask([callback]() { callback(MIN_ROUT_COUNT, 0); }, TaskExecutor::TaskType::JS);
969             });
970         callbackMarkers.emplace(COMMON_COMPLETE, completeEventMarker);
971     }
972 
973     DialogProperties dialogProperties = {
974         .title = title,
975         .content = message,
976         .autoCancel = autoCancel,
977         .buttons = buttons,
978         .callbacks = std::move(callbackMarkers),
979     };
980     auto context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
981     if (context) {
982         context->ShowDialog(dialogProperties, AceApplicationInfo::GetInstance().IsRightToLeft());
983     }
984 }
985 
GetBoundingRectData(NodeId nodeId)986 Rect PluginFrontendDelegate::GetBoundingRectData(NodeId nodeId)
987 {
988     Rect rect;
989     auto task = [context = pipelineContextHolder_.Get(), nodeId, &rect]() {
990         context->GetBoundingRectData(nodeId, rect);
991     };
992     PostSyncTaskToPage(task);
993     return rect;
994 }
995 
GetInspector(NodeId nodeId)996 std::string PluginFrontendDelegate::GetInspector(NodeId nodeId)
997 {
998     std::string attrs;
999     auto task = [weak = WeakClaim(AceType::RawPtr(jsAccessibilityManager_)), nodeId, &attrs]() {
1000         auto accessibilityNodeManager = weak.Upgrade();
1001         if (accessibilityNodeManager) {
1002             attrs = accessibilityNodeManager->GetInspectorNodeById(nodeId);
1003         }
1004     };
1005     PostSyncTaskToPage(task);
1006     return attrs;
1007 }
1008 
SetCallBackResult(const std::string & callBackId,const std::string & result)1009 void PluginFrontendDelegate::SetCallBackResult(const std::string& callBackId, const std::string& result)
1010 {
1011     jsCallBackResult_.try_emplace(StringToInt(callBackId), result);
1012 }
1013 
WaitTimer(const std::string & callbackId,const std::string & delay,bool isInterval,bool isFirst)1014 void PluginFrontendDelegate::WaitTimer(
1015     const std::string& callbackId, const std::string& delay, bool isInterval, bool isFirst)
1016 {
1017     if (!isFirst) {
1018         auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1019         // If not find the callbackId in map, means this timer already was removed,
1020         // no need create a new cancelableTimer again.
1021         if (timeoutTaskIter == timeoutTaskMap_.end()) {
1022             return;
1023         }
1024     }
1025 
1026     int32_t delayTime = StringToInt(delay);
1027     // CancelableCallback class can only be executed once.
1028     CancelableCallback<void()> cancelableTimer;
1029     cancelableTimer.Reset([callbackId, delay, isInterval, call = timer_] { call(callbackId, delay, isInterval); });
1030     auto result = timeoutTaskMap_.try_emplace(callbackId, cancelableTimer);
1031     if (!result.second) {
1032         result.first->second = cancelableTimer;
1033     }
1034     taskExecutor_->PostDelayedTask(cancelableTimer, TaskExecutor::TaskType::JS, delayTime);
1035 }
1036 
ClearTimer(const std::string & callbackId)1037 void PluginFrontendDelegate::ClearTimer(const std::string& callbackId)
1038 {
1039     auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1040     if (timeoutTaskIter != timeoutTaskMap_.end()) {
1041         timeoutTaskIter->second.Cancel();
1042         timeoutTaskMap_.erase(timeoutTaskIter);
1043     } else {
1044         LOGW("ClearTimer callbackId not found");
1045     }
1046 }
1047 
PostSyncTaskToPage(std::function<void ()> && task)1048 void PluginFrontendDelegate::PostSyncTaskToPage(std::function<void()>&& task)
1049 {
1050     pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
1051     taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::UI);
1052 }
1053 
AddTaskObserver(std::function<void ()> && task)1054 void PluginFrontendDelegate::AddTaskObserver(std::function<void()>&& task)
1055 {
1056     taskExecutor_->AddTaskObserver(std::move(task));
1057 }
1058 
RemoveTaskObserver()1059 void PluginFrontendDelegate::RemoveTaskObserver()
1060 {
1061     taskExecutor_->RemoveTaskObserver();
1062 }
1063 
GetAssetContent(const std::string & url,std::string & content)1064 bool PluginFrontendDelegate::GetAssetContent(const std::string& url, std::string& content)
1065 {
1066     return GetAssetContentImpl(assetManager_, url, content);
1067 }
1068 
GetAssetContent(const std::string & url,std::vector<uint8_t> & content)1069 bool PluginFrontendDelegate::GetAssetContent(const std::string& url, std::vector<uint8_t>& content)
1070 {
1071     return GetAssetContentImpl(assetManager_, url, content);
1072 }
1073 
GetAssetPath(const std::string & url)1074 std::string PluginFrontendDelegate::GetAssetPath(const std::string& url)
1075 {
1076     return GetAssetPathImpl(assetManager_, url);
1077 }
1078 
LoadPage(int32_t pageId,const PageTarget & target,bool isMainPage,const std::string & params)1079 void PluginFrontendDelegate::LoadPage(
1080     int32_t pageId, const PageTarget& target, bool isMainPage, const std::string& params)
1081 {
1082     {
1083         std::lock_guard<std::mutex> lock(mutex_);
1084         pageId_ = pageId;
1085         pageParamMap_[pageId] = params;
1086     }
1087     auto url = target.url;
1088     if (pageId == INVALID_PAGE_ID) {
1089         LOGE("PluginFrontendDelegate, invalid page id");
1090         EventReport::SendPageRouterException(PageRouterExcepType::LOAD_PAGE_ERR, url);
1091         return;
1092     }
1093     if (isStagingPageExist_) {
1094         LOGE("PluginFrontendDelegate, load page failed, waiting for current page loading finish.");
1095         RecyclePageId(pageId);
1096         return;
1097     }
1098     isStagingPageExist_ = true;
1099     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1100     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1101     page->SetPageParams(params);
1102     page->SetPluginComponentJsonData(params);
1103     page->SetFlushCallback([weak = AceType::WeakClaim(this), isMainPage](const RefPtr<JsAcePage>& acePage) {
1104         auto delegate = weak.Upgrade();
1105         if (delegate && acePage) {
1106             delegate->FlushPageCommand(acePage, acePage->GetUrl(), isMainPage);
1107         }
1108     });
1109     LoadJS(page, url, isMainPage);
1110 }
1111 
LoadJS(const RefPtr<Framework::JsAcePage> & page,const std::string & url,bool isMainPage)1112 void PluginFrontendDelegate::LoadJS(
1113     const RefPtr<Framework::JsAcePage>& page, const std::string& url, bool isMainPage)
1114 {
1115     taskExecutor_->PostTask(
1116         [weak = AceType::WeakClaim(this), page, url, isMainPage] {
1117             auto delegate = weak.Upgrade();
1118             CHECK_NULL_VOID_NOLOG(delegate);
1119             delegate->loadJs_(url, page, isMainPage);
1120             page->FlushCommands();
1121             // just make sure the pipelineContext is created.
1122             auto pipeline = delegate->pipelineContextHolder_.Get();
1123             pipeline->SetMinPlatformVersion(delegate->GetMinPlatformVersion());
1124             delegate->taskExecutor_->PostTask(
1125                 [weak, page] {
1126                     auto delegate = weak.Upgrade();
1127                     if (delegate && delegate->pipelineContextHolder_.Get()) {
1128                         auto context = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1129                         if (context) {
1130                             context->FlushFocus();
1131                         }
1132                     }
1133                     if (page->GetDomDocument()) {
1134                         page->GetDomDocument()->HandlePageLoadFinish();
1135                     }
1136                 },
1137                 TaskExecutor::TaskType::UI);
1138         },
1139         TaskExecutor::TaskType::JS);
1140 }
1141 
OnSurfaceChanged()1142 void PluginFrontendDelegate::OnSurfaceChanged()
1143 {
1144     if (mediaQueryInfo_->GetIsInit()) {
1145         mediaQueryInfo_->SetIsInit(false);
1146     }
1147     mediaQueryInfo_->EnsureListenerIdValid();
1148     OnMediaQueryUpdate();
1149 }
1150 
OnMediaQueryUpdate()1151 void PluginFrontendDelegate::OnMediaQueryUpdate()
1152 {
1153     if (mediaQueryInfo_->GetIsInit()) {
1154         return;
1155     }
1156 
1157     taskExecutor_->PostTask(
1158         [weak = AceType::WeakClaim(this)] {
1159             auto delegate = weak.Upgrade();
1160             CHECK_NULL_VOID_NOLOG(delegate);
1161             const auto& info = delegate->mediaQueryInfo_->GetMediaQueryInfo();
1162             // request css mediaquery
1163             std::string param("\"viewsizechanged\",");
1164             param.append(info);
1165             delegate->asyncEvent_("_root", param);
1166 
1167             // request js mediaquery
1168             const auto& listenerId = delegate->mediaQueryInfo_->GetListenerId();
1169             delegate->mediaQueryCallback_(listenerId, info);
1170             delegate->mediaQueryInfo_->ResetListenerId();
1171         },
1172         TaskExecutor::TaskType::JS);
1173 }
1174 
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1175 void PluginFrontendDelegate::OnPageReady(
1176     const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1177 {
1178     // Pop all JS command and execute them in UI thread.
1179     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1180     page->PopAllCommands(*jsCommands);
1181 
1182     auto pipelineContext = pipelineContextHolder_.Get();
1183     page->SetPipelineContext(pipelineContext);
1184     taskExecutor_->PostTask(
1185         [weak = AceType::WeakClaim(this), page, url, jsCommands, isMainPage] {
1186             auto delegate = weak.Upgrade();
1187             CHECK_NULL_VOID_NOLOG(delegate);
1188             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1189             CHECK_NULL_VOID(pipelineContext);
1190             // Flush all JS commands.
1191             for (const auto& command : *jsCommands) {
1192                 command->Execute(page);
1193             }
1194             // Just clear all dirty nodes.
1195             page->ClearAllDirtyNodes();
1196             if (page->GetDomDocument()) {
1197                 page->GetDomDocument()->HandleComponentPostBinding();
1198             }
1199             if (pipelineContext->GetAccessibilityManager()) {
1200                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1201             }
1202             if (pipelineContext->CanPushPage()) {
1203                 if (!isMainPage) {
1204                     delegate->OnPageHide();
1205                 }
1206                 delegate->OnPrePageChange(page);
1207                 pipelineContext->PushPage(page->BuildPage(url), page->GetStageElement());
1208                 delegate->OnPushPageSuccess(page, url);
1209                 delegate->SetCurrentPage(page->GetPageId());
1210                 delegate->OnMediaQueryUpdate();
1211             } else {
1212                 // This page has been loaded but become useless now, the corresponding js instance
1213                 // must be destroyed to avoid memory leak.
1214                 delegate->OnPageDestroy(page->GetPageId());
1215                 delegate->ResetStagingPage();
1216             }
1217             delegate->isStagingPageExist_ = false;
1218             if (isMainPage) {
1219                 delegate->OnPageShow();
1220             }
1221         },
1222         TaskExecutor::TaskType::UI);
1223 }
1224 
OnPrePageChange(const RefPtr<JsAcePage> & page)1225 void PluginFrontendDelegate::OnPrePageChange(const RefPtr<JsAcePage>& page)
1226 {
1227     if (page && page->GetDomDocument() && jsAccessibilityManager_) {
1228         jsAccessibilityManager_->SetRootNodeId(page->GetDomDocument()->GetRootNodeId());
1229     }
1230 }
1231 
FlushPageCommand(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1232 void PluginFrontendDelegate::FlushPageCommand(
1233     const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1234 {
1235     CHECK_NULL_VOID_NOLOG(page);
1236     if (page->FragmentCount() == 1) {
1237         OnPageReady(page, url, isMainPage);
1238     } else {
1239         TriggerPageUpdate(page->GetPageId());
1240     }
1241 }
1242 
AddPageLocked(const RefPtr<JsAcePage> & page)1243 void PluginFrontendDelegate::AddPageLocked(const RefPtr<JsAcePage>& page)
1244 {
1245     auto result = pageMap_.try_emplace(page->GetPageId(), page);
1246     if (!result.second) {
1247         LOGW("the page has already in the map");
1248     }
1249 }
1250 
SetCurrentPage(int32_t pageId)1251 void PluginFrontendDelegate::SetCurrentPage(int32_t pageId)
1252 {
1253     auto page = GetPage(pageId);
1254     if (page != nullptr) {
1255         jsAccessibilityManager_->SetVersion(AccessibilityVersion::JS_DECLARATIVE_VERSION);
1256         jsAccessibilityManager_->SetRunningPage(page);
1257         taskExecutor_->PostTask([updatePage = updatePage_, page] { updatePage(page); }, TaskExecutor::TaskType::JS);
1258     } else {
1259         LOGE("PluginFrontendDelegate SetCurrentPage page is null.");
1260     }
1261 }
1262 
OnPushPageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1263 void PluginFrontendDelegate::OnPushPageSuccess(
1264     const RefPtr<JsAcePage>& page, const std::string& url)
1265 {
1266     std::lock_guard<std::mutex> lock(mutex_);
1267     AddPageLocked(page);
1268     pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url});
1269     if (Container::IsCurrentUseNewPipeline()) {
1270         FireDeclarativeOnUpdateWithValueParamsCallback(page->GetPluginComponentJsonData());
1271     } else {
1272         page->FireDeclarativeOnUpdateWithValueParamsCallback(page->GetPluginComponentJsonData());
1273     }
1274     page->FireDeclarativeOnUpdateWithValueParamsCallback(page->GetPluginComponentJsonData());
1275     if (pageRouteStack_.size() >= MAX_ROUTER_STACK) {
1276         isRouteStackFull_ = true;
1277         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, page->GetUrl());
1278     }
1279 }
1280 
OnPopToPageSuccess(const std::string & url)1281 void PluginFrontendDelegate::OnPopToPageSuccess(const std::string& url)
1282 {
1283     std::lock_guard<std::mutex> lock(mutex_);
1284     while (!pageRouteStack_.empty()) {
1285         if (pageRouteStack_.back().url == url) {
1286             break;
1287         }
1288         OnPageDestroy(pageRouteStack_.back().pageId);
1289         pageMap_.erase(pageRouteStack_.back().pageId);
1290         pageParamMap_.erase(pageRouteStack_.back().pageId);
1291         pageRouteStack_.pop_back();
1292     }
1293 
1294     if (isRouteStackFull_) {
1295         isRouteStackFull_ = false;
1296     }
1297 }
1298 
PopToPage(const std::string & url)1299 void PluginFrontendDelegate::PopToPage(const std::string& url)
1300 {
1301     taskExecutor_->PostTask(
1302         [weak = AceType::WeakClaim(this), url] {
1303             auto delegate = weak.Upgrade();
1304             CHECK_NULL_VOID_NOLOG(delegate);
1305             auto pageId = delegate->GetPageIdByUrl(url);
1306             if (pageId == INVALID_PAGE_ID) {
1307                 return;
1308             }
1309             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1310             CHECK_NULL_VOID(pipelineContext);
1311             if (!pipelineContext->CanPopPage()) {
1312                 delegate->ResetStagingPage();
1313                 return;
1314             }
1315             delegate->OnPageHide();
1316             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1317             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1318                 [weak, url, pageId](
1319                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1320                     auto delegate = weak.Upgrade();
1321                     if (delegate) {
1322                         delegate->PopToPageTransitionListener(event, url, pageId);
1323                     }
1324                 });
1325             pipelineContext->PopToPage(pageId);
1326         },
1327         TaskExecutor::TaskType::UI);
1328 }
1329 
PopToPageTransitionListener(const TransitionEvent & event,const std::string & url,int32_t pageId)1330 void PluginFrontendDelegate::PopToPageTransitionListener(
1331     const TransitionEvent& event, const std::string& url, int32_t pageId)
1332 {
1333     if (event == TransitionEvent::POP_END) {
1334         OnPopToPageSuccess(url);
1335         SetCurrentPage(pageId);
1336         OnPageShow();
1337         OnMediaQueryUpdate();
1338     }
1339 }
1340 
OnPopPageSuccess()1341 int32_t PluginFrontendDelegate::OnPopPageSuccess()
1342 {
1343     std::lock_guard<std::mutex> lock(mutex_);
1344     pageMap_.erase(pageRouteStack_.back().pageId);
1345     pageParamMap_.erase(pageRouteStack_.back().pageId);
1346     pageRouteStack_.pop_back();
1347     if (isRouteStackFull_) {
1348         isRouteStackFull_ = false;
1349     }
1350     if (!pageRouteStack_.empty()) {
1351         return pageRouteStack_.back().pageId;
1352     }
1353     return INVALID_PAGE_ID;
1354 }
1355 
PopPage()1356 void PluginFrontendDelegate::PopPage()
1357 {
1358     taskExecutor_->PostTask(
1359         [weak = AceType::WeakClaim(this)] {
1360             auto delegate = weak.Upgrade();
1361             CHECK_NULL_VOID_NOLOG(delegate);
1362             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1363             CHECK_NULL_VOID(pipelineContext);
1364             if (delegate->GetStackSize() == 1) {
1365                 if (delegate->disallowPopLastPage_) {
1366                     LOGW("Not allow back because this is the last page!");
1367                     return;
1368                 }
1369                 delegate->OnPageHide();
1370                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1371                 delegate->OnPopPageSuccess();
1372                 pipelineContext->Finish();
1373                 return;
1374             }
1375             if (!pipelineContext->CanPopPage()) {
1376                 delegate->ResetStagingPage();
1377                 return;
1378             }
1379             delegate->OnPageHide();
1380             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1381             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1382                 [weak, destroyPageId = delegate->GetRunningPageId()](
1383                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1384                     auto delegate = weak.Upgrade();
1385                     if (delegate) {
1386                         delegate->PopPageTransitionListener(event, destroyPageId);
1387                     }
1388                 });
1389             pipelineContext->PopPage();
1390         },
1391         TaskExecutor::TaskType::UI);
1392 }
1393 
PopPageTransitionListener(const TransitionEvent & event,int32_t destroyPageId)1394 void PluginFrontendDelegate::PopPageTransitionListener(
1395     const TransitionEvent& event, int32_t destroyPageId)
1396 {
1397     if (event == TransitionEvent::POP_END) {
1398         OnPageDestroy(destroyPageId);
1399         auto pageId = OnPopPageSuccess();
1400         SetCurrentPage(pageId);
1401         OnPageShow();
1402         OnMediaQueryUpdate();
1403     }
1404 }
1405 
OnClearInvisiblePagesSuccess()1406 int32_t PluginFrontendDelegate::OnClearInvisiblePagesSuccess()
1407 {
1408     std::lock_guard<std::mutex> lock(mutex_);
1409     PageInfo pageInfo = std::move(pageRouteStack_.back());
1410     pageRouteStack_.pop_back();
1411     for (const auto& info : pageRouteStack_) {
1412         OnPageDestroy(info.pageId);
1413         pageMap_.erase(info.pageId);
1414         pageParamMap_.erase(info.pageId);
1415     }
1416     pageRouteStack_.clear();
1417     int32_t resPageId = pageInfo.pageId;
1418     pageRouteStack_.emplace_back(std::move(pageInfo));
1419     if (isRouteStackFull_) {
1420         isRouteStackFull_ = false;
1421     }
1422     return resPageId;
1423 }
1424 
ClearInvisiblePages()1425 void PluginFrontendDelegate::ClearInvisiblePages()
1426 {
1427     taskExecutor_->PostTask(
1428         [weak = AceType::WeakClaim(this)] {
1429             auto delegate = weak.Upgrade();
1430             CHECK_NULL_VOID_NOLOG(delegate);
1431             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1432             CHECK_NULL_VOID(pipelineContext);
1433             if (pipelineContext->ClearInvisiblePages()) {
1434                 auto pageId = delegate->OnClearInvisiblePagesSuccess();
1435                 delegate->SetCurrentPage(pageId);
1436             }
1437         },
1438         TaskExecutor::TaskType::UI);
1439 }
1440 
OnReplacePageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1441 void PluginFrontendDelegate::OnReplacePageSuccess(
1442     const RefPtr<JsAcePage>& page, const std::string& url)
1443 {
1444     CHECK_NULL_VOID_NOLOG(page);
1445     std::lock_guard<std::mutex> lock(mutex_);
1446     AddPageLocked(page);
1447     if (!pageRouteStack_.empty()) {
1448         pageMap_.erase(pageRouteStack_.back().pageId);
1449         pageParamMap_.erase(pageRouteStack_.back().pageId);
1450         pageRouteStack_.pop_back();
1451     }
1452     pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url});
1453 }
1454 
ReplacePage(const RefPtr<JsAcePage> & page,const std::string & url)1455 void PluginFrontendDelegate::ReplacePage(
1456     const RefPtr<JsAcePage>& page, const std::string& url)
1457 {
1458     // Pop all JS command and execute them in UI thread.
1459     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1460     page->PopAllCommands(*jsCommands);
1461 
1462     auto pipelineContext = pipelineContextHolder_.Get();
1463     page->SetPipelineContext(pipelineContext);
1464     taskExecutor_->PostTask(
1465         [weak = AceType::WeakClaim(this), page, url, jsCommands] {
1466             auto delegate = weak.Upgrade();
1467             CHECK_NULL_VOID_NOLOG(delegate);
1468             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1469             CHECK_NULL_VOID(pipelineContext);
1470             // Flush all JS commands.
1471             for (const auto& command : *jsCommands) {
1472                 command->Execute(page);
1473             }
1474             // Just clear all dirty nodes.
1475             page->ClearAllDirtyNodes();
1476             page->GetDomDocument()->HandleComponentPostBinding();
1477             if (pipelineContext->GetAccessibilityManager()) {
1478                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1479             }
1480             if (pipelineContext->CanReplacePage()) {
1481                 delegate->OnPageHide();
1482                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1483                 delegate->OnPrePageChange(page);
1484                 pipelineContext->ReplacePage(page->BuildPage(url), page->GetStageElement());
1485                 delegate->OnReplacePageSuccess(page, url);
1486                 delegate->SetCurrentPage(page->GetPageId());
1487                 delegate->OnMediaQueryUpdate();
1488             } else {
1489                 // This page has been loaded but become useless now, the corresponding js instance
1490                 // must be destroyed to avoid memory leak.
1491                 delegate->OnPageDestroy(page->GetPageId());
1492                 delegate->ResetStagingPage();
1493             }
1494             delegate->isStagingPageExist_ = false;
1495         },
1496         TaskExecutor::TaskType::UI);
1497 }
1498 
LoadReplacePage(int32_t pageId,const PageTarget & target,const std::string & params)1499 void PluginFrontendDelegate::LoadReplacePage(int32_t pageId, const PageTarget& target, const std::string& params)
1500 {
1501     {
1502         std::lock_guard<std::mutex> lock(mutex_);
1503         pageId_ = pageId;
1504         pageParamMap_[pageId] = params;
1505     }
1506     auto url = target.url;
1507     if (pageId == INVALID_PAGE_ID) {
1508         LOGE("PluginFrontendDelegate, invalid page id");
1509         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1510         return;
1511     }
1512     if (isStagingPageExist_) {
1513         LOGE("PluginFrontendDelegate, replace page failed, waiting for current page loading finish.");
1514         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1515         return;
1516     }
1517     isStagingPageExist_ = true;
1518     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1519     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1520     page->SetPageParams(params);
1521     taskExecutor_->PostTask(
1522         [page, url, weak = AceType::WeakClaim(this)] {
1523             auto delegate = weak.Upgrade();
1524             if (delegate) {
1525                 delegate->loadJs_(url, page, false);
1526                 delegate->ReplacePage(page, url);
1527             }
1528         },
1529         TaskExecutor::TaskType::JS);
1530 }
1531 
SetColorMode(ColorMode colorMode)1532 void PluginFrontendDelegate::SetColorMode(ColorMode colorMode)
1533 {
1534     OnMediaQueryUpdate();
1535 }
1536 
RebuildAllPages()1537 void PluginFrontendDelegate::RebuildAllPages()
1538 {
1539     std::unordered_map<int32_t, RefPtr<JsAcePage>> pages;
1540     {
1541         std::lock_guard<std::mutex> lock(mutex_);
1542         pages.insert(pageMap_.begin(), pageMap_.end());
1543     }
1544     for (const auto& [pageId, page] : pages) {
1545         page->FireDeclarativeOnPageRefreshCallback();
1546         TriggerPageUpdate(page->GetPageId(), true);
1547     }
1548 }
1549 
OnPageShow()1550 void PluginFrontendDelegate::OnPageShow()
1551 {
1552     auto pageId = GetRunningPageId();
1553     auto page = GetPage(pageId);
1554     if (page) {
1555         page->FireDeclarativeOnPageAppearCallback();
1556     }
1557     FireAsyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
1558 }
1559 
OnPageHide()1560 void PluginFrontendDelegate::OnPageHide()
1561 {
1562     auto pageId = GetRunningPageId();
1563     auto page = GetPage(pageId);
1564     if (page) {
1565         page->FireDeclarativeOnPageDisAppearCallback();
1566     }
1567     FireAsyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
1568 }
1569 
OnPageDestroy(int32_t pageId)1570 void PluginFrontendDelegate::OnPageDestroy(int32_t pageId)
1571 {
1572     taskExecutor_->PostTask(
1573         [weak = AceType::WeakClaim(this), pageId] {
1574             auto delegate = weak.Upgrade();
1575             if (delegate) {
1576                 delegate->destroyPage_(pageId);
1577                 delegate->RecyclePageId(pageId);
1578             }
1579         },
1580         TaskExecutor::TaskType::JS);
1581 }
1582 
GetRunningPageId() const1583 int32_t PluginFrontendDelegate::GetRunningPageId() const
1584 {
1585     std::lock_guard<std::mutex> lock(mutex_);
1586     if (pageRouteStack_.empty()) {
1587         return INVALID_PAGE_ID;
1588     }
1589     return pageRouteStack_.back().pageId;
1590 }
1591 
GetRunningPageUrl() const1592 std::string PluginFrontendDelegate::GetRunningPageUrl() const
1593 {
1594     std::lock_guard<std::mutex> lock(mutex_);
1595     if (pageRouteStack_.empty()) {
1596         return std::string();
1597     }
1598     const auto& pageUrl = pageRouteStack_.back().url;
1599     auto pos = pageUrl.rfind(".js");
1600     if (pos == pageUrl.length() - JS_HEADER_OFFSET) {
1601         return pageUrl.substr(0, pos);
1602     }
1603     return pageUrl;
1604 }
1605 
GetPageIdByUrl(const std::string & url)1606 int32_t PluginFrontendDelegate::GetPageIdByUrl(const std::string& url)
1607 {
1608     std::lock_guard<std::mutex> lock(mutex_);
1609     auto pageIter = std::find_if(std::rbegin(pageRouteStack_), std::rend(pageRouteStack_),
1610         [&url](const PageInfo& pageRoute) { return url == pageRoute.url; });
1611     if (pageIter != std::rend(pageRouteStack_)) {
1612         LOGW("GetPageIdByUrl pageId=%{private}d url=%{private}s", pageIter->pageId, url.c_str());
1613         return pageIter->pageId;
1614     }
1615     return INVALID_PAGE_ID;
1616 }
1617 
GetPage(int32_t pageId) const1618 RefPtr<JsAcePage> PluginFrontendDelegate::GetPage(int32_t pageId) const
1619 {
1620     std::lock_guard<std::mutex> lock(mutex_);
1621     auto itPage = pageMap_.find(pageId);
1622     if (itPage == pageMap_.end()) {
1623         LOGE("the page is not in the map");
1624         return nullptr;
1625     }
1626     return itPage->second;
1627 }
1628 
RegisterFont(const std::string & familyName,const std::string & familySrc)1629 void PluginFrontendDelegate::RegisterFont(const std::string& familyName, const std::string& familySrc)
1630 {
1631     pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc);
1632 }
1633 
HandleImage(const std::string & src,std::function<void (bool,int32_t,int32_t)> && callback)1634 void PluginFrontendDelegate::HandleImage(
1635     const std::string& src, std::function<void(bool, int32_t, int32_t)>&& callback)
1636 {
1637     if (src.empty() || !callback) {
1638         return;
1639     }
1640     auto loadCallback = [jsCallback = std::move(callback), taskExecutor = taskExecutor_](
1641                             bool success, int32_t width, int32_t height) {
1642         taskExecutor->PostTask(
1643             [callback = std::move(jsCallback), success, width, height] { callback(success, width, height); },
1644             TaskExecutor::TaskType::JS);
1645     };
1646     pipelineContextHolder_.Get()->TryLoadImageInfo(src, std::move(loadCallback));
1647 }
1648 
PushJsCallbackToRenderNode(NodeId id,double ratio,std::function<void (bool,double)> && callback)1649 void PluginFrontendDelegate::PushJsCallbackToRenderNode(NodeId id, double ratio,
1650     std::function<void(bool, double)>&& callback)
1651 {
1652     LOGW("Not implement in declarative frontend.");
1653 }
1654 
RequestAnimationFrame(const std::string & callbackId)1655 void PluginFrontendDelegate::RequestAnimationFrame(const std::string& callbackId)
1656 {
1657     CancelableCallback<void()> cancelableTask;
1658     cancelableTask.Reset([callbackId, call = requestAnimationCallback_, weak = AceType::WeakClaim(this)] {
1659         auto delegate = weak.Upgrade();
1660         if (delegate && call) {
1661             call(callbackId, delegate->GetSystemRealTime());
1662         }
1663     });
1664     animationFrameTaskMap_.try_emplace(callbackId, cancelableTask);
1665     animationFrameTaskIds_.emplace(callbackId);
1666 }
1667 
GetSystemRealTime()1668 uint64_t PluginFrontendDelegate::GetSystemRealTime()
1669 {
1670     struct timespec ts;
1671     clock_gettime(CLOCK_REALTIME, &ts);
1672     return ts.tv_sec * TO_MILLI + ts.tv_nsec / NANO_TO_MILLI;
1673 }
1674 
CancelAnimationFrame(const std::string & callbackId)1675 void PluginFrontendDelegate::CancelAnimationFrame(const std::string& callbackId)
1676 {
1677     auto animationTaskIter = animationFrameTaskMap_.find(callbackId);
1678     if (animationTaskIter != animationFrameTaskMap_.end()) {
1679         animationTaskIter->second.Cancel();
1680         animationFrameTaskMap_.erase(animationTaskIter);
1681     } else {
1682         LOGW("cancelAnimationFrame callbackId not found");
1683     }
1684 }
1685 
FlushAnimationTasks()1686 void PluginFrontendDelegate::FlushAnimationTasks()
1687 {
1688     while (!animationFrameTaskIds_.empty()) {
1689         const auto& callbackId = animationFrameTaskIds_.front();
1690         if (!callbackId.empty()) {
1691             auto taskIter = animationFrameTaskMap_.find(callbackId);
1692             if (taskIter != animationFrameTaskMap_.end()) {
1693                 taskExecutor_->PostTask(taskIter->second, TaskExecutor::TaskType::JS);
1694             }
1695         }
1696         animationFrameTaskIds_.pop();
1697     }
1698 }
1699 
GetAnimationJsTask()1700 SingleTaskExecutor PluginFrontendDelegate::GetAnimationJsTask()
1701 {
1702     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::JS);
1703 }
1704 
GetUiTask()1705 SingleTaskExecutor PluginFrontendDelegate::GetUiTask()
1706 {
1707     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::UI);
1708 }
1709 
AttachPipelineContext(const RefPtr<PipelineBase> & context)1710 void PluginFrontendDelegate::AttachPipelineContext(const RefPtr<PipelineBase>& context)
1711 {
1712     CHECK_NULL_VOID_NOLOG(context);
1713     context->SetOnPageShow([weak = AceType::WeakClaim(this)] {
1714         auto delegate = weak.Upgrade();
1715         if (delegate) {
1716             delegate->OnPageShow();
1717         }
1718     });
1719     context->SetAnimationCallback([weak = AceType::WeakClaim(this)] {
1720         auto delegate = weak.Upgrade();
1721         if (delegate) {
1722             delegate->FlushAnimationTasks();
1723         }
1724     });
1725     pipelineContextHolder_.Attach(context);
1726     jsAccessibilityManager_->SetPipelineContext(context);
1727     jsAccessibilityManager_->InitializeCallback();
1728 }
1729 
GetPipelineContext()1730 RefPtr<PipelineBase> PluginFrontendDelegate::GetPipelineContext()
1731 {
1732     return pipelineContextHolder_.Get();
1733 }
1734 
UpdatePlugin(const std::string & content)1735 void PluginFrontendDelegate::UpdatePlugin(const std::string& content)
1736 {
1737     auto pageId = GetRunningPageId();
1738     auto page = GetPage(pageId);
1739     if (Container::IsCurrentUseNewPipeline()) {
1740         FireDeclarativeOnUpdateWithValueParamsCallback(content);
1741         return;
1742     }
1743     if (page) {
1744         page->FireDeclarativeOnUpdateWithValueParamsCallback(content);
1745     }
1746 }
1747 } // namespace OHOS::Ace::Framework
1748