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