• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "bridge/cj_frontend/frontend/cj_frontend_abstract.h"
17 
18 #include "base/i18n/localization.h"
19 #include "base/subwindow/subwindow_manager.h"
20 #include "bridge/cj_frontend/frontend/cj_frontend_loader.h"
21 #include "bridge/cj_frontend/runtime/cj_runtime_delegate.h"
22 #include "bridge/common/accessibility/accessibility_node_manager.h"
23 #include "core/common/font_manager.h"
24 #include "core/pipeline_ng/pipeline_context.h"
25 #include "securec.h"
26 
27 using namespace OHOS::Ace::NG;
28 using namespace OHOS::Ace;
29 
30 namespace OHOS::Ace {
31 namespace {
32 constexpr int32_t TOAST_TIME_MAX = 10000;    // ms
33 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
34 constexpr int32_t CALLBACK_ERRORCODE_CANCEL = 1;
35 constexpr int32_t CALLBACK_DATACODE_ZERO = 0;
36 
37 // helper function to run OverlayManager task
38 // ensures that the task runs in subwindow instead of main Window
MainWindowOverlay(std::function<void (RefPtr<NG::OverlayManager>)> && task,const std::string & name)39 void MainWindowOverlay(std::function<void(RefPtr<NG::OverlayManager>)>&& task, const std::string& name)
40 {
41     auto currentId = Container::CurrentId();
42     ContainerScope scope(currentId);
43     auto context = NG::PipelineContext::GetCurrentContext();
44     CHECK_NULL_VOID(context);
45     auto overlayManager = context->GetOverlayManager();
46     context->GetTaskExecutor()->PostTask(
47         [task = std::move(task), weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
48             auto overlayManager = weak.Upgrade();
49             task(overlayManager);
50         },
51         TaskExecutor::TaskType::UI, name);
52 }
53 } // namespace
54 
55 #if defined(PREVIEW)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const56 void CJFrontendAbstract::TransferJsResponseDataPreview(
57     int32_t callbackId, int32_t code, ResponseData responseData) const
58 {}
59 #endif
60 
~CJFrontendAbstract()61 CJFrontendAbstract::~CJFrontendAbstract()
62 {
63     LOGD("CJFrontendAbstract destroyed.");
64 }
65 
Initialize(FrontendType type,const RefPtr<OHOS::Ace::TaskExecutor> & taskExecutor)66 bool CJFrontendAbstract::Initialize(FrontendType type, const RefPtr<OHOS::Ace::TaskExecutor>& taskExecutor)
67 {
68     if (type != FrontendType::DECLARATIVE_CJ) {
69         LOGE("CJFrontendAbstract Initialize failed, FrontendType only accept DECLARATIVE_CJ");
70         return false;
71     }
72     LOGD("CJFrontendAbstract initialize begin.");
73     taskExecutor_ = taskExecutor;
74     manifestParser_ = AceType::MakeRefPtr<Framework::ManifestParser>();
75     accessibilityManager_ = Framework::AccessibilityNodeManager::Create();
76 
77     type_ = type;
78     InternalInitialize();
79     if (!pageRouterManager_) {
80         LOGE("InternalInitialize must initialize pageRouterManager_");
81         return false;
82     }
83     return true;
84 }
85 
FlushReload()86 void CJFrontendAbstract::FlushReload()
87 {
88     if (!Container::IsCurrentUseNewPipeline()) {
89         LOGW("not support old pipeline");
90         return;
91     }
92     pageRouterManager_->FlushReload();
93 }
94 
RebuildAllPages()95 void CJFrontendAbstract::RebuildAllPages()
96 {
97     CHECK_NULL_VOID(pageRouterManager_);
98     auto url = pageRouterManager_->GetCurrentPageUrl();
99     pageRouterManager_->Clear();
100     pageRouterManager_->RunPage(url, "");
101 }
102 
NavigatePage(uint8_t type,const PageTarget & target,const std::string & params)103 void CJFrontendAbstract::NavigatePage(uint8_t type, const PageTarget& target, const std::string& params)
104 {
105     switch (static_cast<NavigatorType>(type)) {
106         case NavigatorType::PUSH:
107             PushPage(target.url, params);
108             break;
109         case NavigatorType::REPLACE:
110             ReplacePage(target.url, params);
111             break;
112         case NavigatorType::BACK:
113             Back(target.url, params);
114             break;
115         default:
116             LOGE("Navigator type is invalid!");
117             Back(target.url, params);
118     }
119 }
120 
OnBackPressed()121 bool CJFrontendAbstract::OnBackPressed()
122 {
123     return pageRouterManager_->PopWithExitCheck();
124 }
125 
OnShow()126 void CJFrontendAbstract::OnShow()
127 {
128     foregroundFrontend_ = true;
129     pageRouterManager_->OnShowCurrent();
130 }
131 
OnHide()132 void CJFrontendAbstract::OnHide()
133 {
134     foregroundFrontend_ = false;
135     pageRouterManager_->OnHideCurrent();
136 }
137 
Destroy()138 void CJFrontendAbstract::Destroy()
139 {
140     LOGD("CJFrontendAbstract Destroy begin.");
141 }
142 
CheckLoadAppLibrary()143 bool CJFrontendAbstract::CheckLoadAppLibrary()
144 {
145     return Framework::CJRuntimeDelegate::GetInstance()->CheckLoadCJLibrary();
146 }
147 
AttachPipelineContext(const RefPtr<PipelineBase> & context)148 void CJFrontendAbstract::AttachPipelineContext(const RefPtr<PipelineBase>& context)
149 {
150     pipelineContextHolder_.Attach(context);
151     auto jsAccessibility = AceType::DynamicCast<Framework::AccessibilityNodeManager>(accessibilityManager_);
152     jsAccessibility->SetPipelineContext(context);
153     jsAccessibility->InitializeCallback();
154 }
155 
SetAssetManager(const RefPtr<AssetManager> & assetManager)156 void CJFrontendAbstract::SetAssetManager(const RefPtr<AssetManager>& assetManager)
157 {
158     assetManager_ = assetManager;
159 }
160 
RunPage(const std::string & url,const std::string & params)161 UIContentErrorCode CJFrontendAbstract::RunPage(const std::string& url, const std::string& params)
162 {
163     LOGI("CJFrontendAbstract::RunPage start: %{public}s", url.c_str());
164     if (!isStageModel_) {
165         if (!CheckLoadAppLibrary()) {
166             TAG_LOGW(AceLogTag::ACE_FORM, "fail to run page due to path url is empty");
167             return UIContentErrorCode::NULL_URL;
168         }
169     }
170     InternalRunPage(url, params);
171     return UIContentErrorCode::NO_ERRORS;
172 }
173 
ReplacePage(const std::string & url,const std::string & params)174 void CJFrontendAbstract::ReplacePage(const std::string& url, const std::string& params)
175 {
176     pageRouterManager_->Replace({ url }, params);
177 }
178 
PushPage(const std::string & url,const std::string & params)179 void CJFrontendAbstract::PushPage(const std::string& url, const std::string& params)
180 {
181     pageRouterManager_->Push({ url }, params);
182 }
183 
Back(const std::string & uri,const std::string & params)184 void CJFrontendAbstract::Back(const std::string& uri, const std::string& params)
185 {
186     pageRouterManager_->BackWithTarget({ uri }, params);
187 }
188 
CallRouterBack()189 void CJFrontendAbstract::CallRouterBack()
190 {
191     pageRouterManager_->Pop();
192 }
193 
InternalRunPage(const std::string & url,const std::string & params)194 void CJFrontendAbstract::InternalRunPage(const std::string& url, const std::string& params)
195 {
196     LOGI("InternalRunPage %{public}s", url.c_str());
197     pageRouterManager_->RunPage(url, params);
198 }
199 
MeasureText(const MeasureContext & context)200 double CJFrontendAbstract::MeasureText(const MeasureContext& context)
201 {
202     return MeasureUtil::MeasureText(context);
203 }
204 
MeasureTextSize(const MeasureContext & context)205 Size CJFrontendAbstract::MeasureTextSize(const MeasureContext& context)
206 {
207     LOGI("CJFrontendAbstract::MeasureTextSize start");
208     return MeasureUtil::MeasureTextSize(context);
209 }
210 
ShowToast(const std::string & message,int32_t duration,const std::string & bottom,const NG::ToastShowMode & showMode)211 void CJFrontendAbstract::ShowToast(
212     const std::string& message, int32_t duration, const std::string& bottom, const NG::ToastShowMode& showMode)
213 {
214     int32_t durationTime = std::clamp(duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
215     bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
216     auto task = [durationTime, message, bottom, isRightToLeft, showMode, containerId = Container::CurrentId()](
217                     const RefPtr<NG::OverlayManager>& overlayManager) {
218         CHECK_NULL_VOID(overlayManager);
219         ContainerScope scope(containerId);
220         auto toastInfo = NG::ToastInfo { .message = message,
221             .duration = durationTime,
222             .bottom = bottom,
223             .isRightToLeft = isRightToLeft,
224             .showMode = showMode,
225             .alignment = -1,
226             .offset = std::nullopt };
227         overlayManager->ShowToast(toastInfo, nullptr);
228     };
229     MainWindowOverlay(std::move(task), "ArkUIOverlayShowToast");
230 }
231 
ShowDialog(const std::string & title,const std::string & message,const std::vector<ButtonInfo> & buttons,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)232 void CJFrontendAbstract::ShowDialog(const std::string& title, const std::string& message,
233     const std::vector<ButtonInfo>& buttons, std::function<void(int32_t, int32_t)>&& callback,
234     const std::set<std::string>& callbacks)
235 {
236     DialogProperties dialogProperties = { .title = title, .content = message, .buttons = buttons };
237     ShowDialogInner(dialogProperties, std::move(callback), callbacks);
238 }
239 
ShowDialogInner(DialogProperties & dialogProperties,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)240 void CJFrontendAbstract::ShowDialogInner(DialogProperties& dialogProperties,
241     std::function<void(int32_t, int32_t)>&& callback, const std::set<std::string>& callbacks)
242 {
243     auto pipelineContext = pipelineContextHolder_.Get();
244     LOGI("Dialog IsCurrentUseNewPipeline.");
245     dialogProperties.onCancel = [callback, taskExecutor = taskExecutor_] {
246         taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
247             TaskExecutor::TaskType::JS, "CJFroentendShowDialogInner");
248     };
249     dialogProperties.onSuccess = std::move(callback);
250     auto task = [dialogProperties](const RefPtr<NG::OverlayManager>& overlayManager) {
251         CHECK_NULL_VOID(overlayManager);
252         RefPtr<NG::FrameNode> dialog;
253         LOGI("Begin to show dialog ");
254         if (dialogProperties.isShowInSubWindow) {
255             dialog = SubwindowManager::GetInstance()->ShowDialogNG(dialogProperties, nullptr);
256             CHECK_NULL_VOID(dialog);
257             if (dialogProperties.isModal) {
258                 DialogProperties maskarg;
259                 maskarg.isMask = true;
260                 maskarg.autoCancel = dialogProperties.autoCancel;
261                 auto mask = overlayManager->ShowDialog(maskarg, nullptr, false);
262                 CHECK_NULL_VOID(mask);
263                 overlayManager->SetMaskNodeId(dialog->GetId(), mask->GetId());
264             }
265         } else {
266             dialog = overlayManager->ShowDialog(
267                 dialogProperties, nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
268             CHECK_NULL_VOID(dialog);
269         }
270     };
271     MainWindowOverlay(std::move(task), "ArkUIShowDialogInner");
272 }
273 
ShowActionMenu(const std::string & title,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)274 void CJFrontendAbstract::ShowActionMenu(
275     const std::string& title, const std::vector<ButtonInfo>& button, std::function<void(int32_t, int32_t)>&& callback)
276 {
277     DialogProperties dialogProperties = {
278         .title = title,
279         .autoCancel = true,
280         .isMenu = true,
281         .buttons = button,
282     };
283     ShowActionMenuInner(dialogProperties, button, std::move(callback));
284 }
285 
ShowActionMenuInner(DialogProperties & dialogProperties,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)286 void CJFrontendAbstract::ShowActionMenuInner(DialogProperties& dialogProperties, const std::vector<ButtonInfo>& button,
287     std::function<void(int32_t, int32_t)>&& callback)
288 {
289     ButtonInfo buttonInfo = { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" };
290     dialogProperties.buttons.emplace_back(buttonInfo);
291     dialogProperties.onCancel = [callback, taskExecutor = taskExecutor_] {
292         taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
293             TaskExecutor::TaskType::JS, "CJFroentendShowActionMenuInnerOnCancel");
294     };
295     dialogProperties.onSuccess = std::move(callback);
296     auto context = DynamicCast<NG::PipelineContext>(pipelineContextHolder_.Get());
297     auto overlayManager = context ? context->GetOverlayManager() : nullptr;
298     taskExecutor_->PostTask(
299         [dialogProperties, weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
300             auto overlayManager = weak.Upgrade();
301             CHECK_NULL_VOID(overlayManager);
302             RefPtr<NG::FrameNode> dialog;
303             if (dialogProperties.isShowInSubWindow) {
304                 dialog = SubwindowManager::GetInstance()->ShowDialogNG(dialogProperties, nullptr);
305                 CHECK_NULL_VOID(dialog);
306                 if (dialogProperties.isModal) {
307                     DialogProperties maskarg;
308                     maskarg.autoCancel = dialogProperties.autoCancel;
309                     maskarg.isMask = true;
310                     auto mask = overlayManager->ShowDialog(maskarg, nullptr, false);
311                     CHECK_NULL_VOID(mask);
312                     overlayManager->SetMaskNodeId(dialog->GetId(), mask->GetId());
313                 }
314             } else {
315                 dialog = overlayManager->ShowDialog(
316                     dialogProperties, nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
317                 CHECK_NULL_VOID(dialog);
318             }
319         },
320         TaskExecutor::TaskType::UI, "CJFroentendShowActionMenuInner");
321 }
322 
OpenCustomDialog(const PromptDialogAttr & dialogAttr,std::function<void (int32_t)> && callback)323 void CJFrontendAbstract::OpenCustomDialog(const PromptDialogAttr& dialogAttr, std::function<void(int32_t)>&& callback)
324 {
325     DialogProperties dialogProperties = { .onWillDismiss = dialogAttr.customOnWillDismiss,
326         .isShowInSubWindow = dialogAttr.showInSubWindow,
327         .isModal = dialogAttr.isModal,
328         .isSysBlurStyle = false,
329         .customBuilder = dialogAttr.customBuilder,
330         .maskRect = dialogAttr.maskRect };
331 #if defined(PREVIEW)
332     if (dialogProperties.isShowInSubWindow) {
333         LOGW("[Engine Log] Unable to use the SubWindow in the Previewer. Perform this operation on the "
334              "emulator or a real device instead.");
335         dialogProperties.isShowInSubWindow = false;
336     }
337 #endif
338     if (dialogAttr.alignment.has_value()) {
339         dialogProperties.alignment = dialogAttr.alignment.value();
340     }
341     if (dialogAttr.offset.has_value()) {
342         dialogProperties.offset = dialogAttr.offset.value();
343     }
344     if (!Container::IsCurrentUseNewPipeline()) {
345         LOGW("not support old pipeline");
346         return;
347     }
348     LOGI("Dialog IsCurrentUseNewPipeline.");
349     auto task = [dialogAttr, dialogProperties, callback](const RefPtr<NG::OverlayManager>& overlayManager) mutable {
350         CHECK_NULL_VOID(overlayManager);
351         LOGI("Begin to open custom dialog ");
352         if (dialogProperties.isShowInSubWindow) {
353             SubwindowManager::GetInstance()->OpenCustomDialogNG(dialogProperties, std::move(callback));
354             if (dialogProperties.isModal) {
355                 LOGW("temporary not support isShowInSubWindow and isModal");
356             }
357         } else {
358             overlayManager->OpenCustomDialog(dialogProperties, std::move(callback));
359         }
360     };
361     MainWindowOverlay(std::move(task), "ArkUIOpenCustomDialog");
362     return;
363 }
364 
CloseCustomDialog(int32_t id)365 void CJFrontendAbstract::CloseCustomDialog(int32_t id)
366 {
367     auto task = [id](const RefPtr<NG::OverlayManager>& overlayManager) {
368         CHECK_NULL_VOID(overlayManager);
369         LOGI("begin to close custom dialog.");
370         overlayManager->CloseCustomDialog(id);
371         SubwindowManager::GetInstance()->CloseCustomDialogNG(id);
372     };
373     MainWindowOverlay(std::move(task), "ArkUICloseCustomDialog");
374     return;
375 }
376 
RegisterFont(const std::string & familyName,const std::string & familySrc,const std::string & bundleName,const std::string & moduleName)377 void CJFrontendAbstract::RegisterFont(const std::string& familyName, const std::string& familySrc,
378     const std::string& bundleName, const std::string& moduleName)
379 {
380     pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc, bundleName, moduleName);
381 }
382 
GetSystemFontList()383 VectorStringHandle CJFrontendAbstract::GetSystemFontList()
384 {
385     auto fontList = new std::vector<std::string>;
386     pipelineContextHolder_.Get()->GetSystemFontList(*fontList);
387     return fontList;
388 }
389 
GetSystemFont(const std::string & fontName)390 NativeOptionFontInfo CJFrontendAbstract::GetSystemFont(const std::string& fontName)
391 {
392     FontInfo fontInfo;
393     if (!pipelineContextHolder_.Get()->GetSystemFont(fontName, fontInfo)) {
394         return NativeOptionFontInfo { .hasValue = false, .info = nullptr };
395     }
396     return NativeOptionFontInfo { .hasValue = true,
397         .info = new NativeFontInfo { .path = fontInfo.path.c_str(),
398             .postScriptName = fontInfo.postScriptName.c_str(),
399             .fullName = fontInfo.fullName.c_str(),
400             .family = fontInfo.family.c_str(),
401             .subfamily = fontInfo.subfamily.c_str(),
402             .weight = fontInfo.weight,
403             .width = fontInfo.width,
404             .italic = fontInfo.italic,
405             .monoSpace = fontInfo.monoSpace,
406             .symbolic = fontInfo.symbolic } };
407 }
BackIndex(int32_t index,const std::string & params)408 void CJFrontendAbstract::BackIndex(int32_t index, const std::string& params)
409 {
410     pageRouterManager_->BackWithIndex(index, params);
411 }
412 
Clear()413 void CJFrontendAbstract::Clear()
414 {
415     pageRouterManager_->Clear();
416 }
417 
GetLength()418 int32_t CJFrontendAbstract::GetLength()
419 {
420     return pageRouterManager_->GetStackSize();
421 }
422 
SetShowAlertBeforeBackPage(const char * msg,std::function<void (int32_t)> && callback)423 void CJFrontendAbstract::SetShowAlertBeforeBackPage(const char* msg, std::function<void(int32_t)>&& callback)
424 {
425     pageRouterManager_->EnableAlertBeforeBackPage(msg, callback);
426 }
427 
SetHideAlertBeforeBackPage()428 void CJFrontendAbstract::SetHideAlertBeforeBackPage()
429 {
430     pageRouterManager_->DisableAlertBeforeBackPage();
431 }
432 
CopyStr(const std::string & str)433 static char* CopyStr(const std::string& str)
434 {
435     char* newStr = new (std::nothrow) char[str.length() + 1];
436     if (newStr == nullptr) {
437         return nullptr;
438     }
439 
440     int err = strcpy_s(newStr, str.length() + 1, str.c_str());
441     if (err != 0) {
442         delete[] newStr;
443         return nullptr;
444     }
445 
446     return newStr;
447 }
448 
GetState(CJPageRouterAbstract::RouterState * info)449 void CJFrontendAbstract::GetState(CJPageRouterAbstract::RouterState* info)
450 {
451     std::string name_str = "";
452     std::string path_str = "";
453     std::string params_str = "";
454     pageRouterManager_->GetState(info->index, name_str, path_str, params_str);
455     info->name = CopyStr(name_str);
456     info->path = CopyStr(path_str);
457     info->params = CopyStr(params_str);
458 }
459 
GetStateByIndex(CJPageRouterAbstract::RouterState * info)460 void CJFrontendAbstract::GetStateByIndex(CJPageRouterAbstract::RouterState* info)
461 {
462     std::string name_str = "";
463     std::string path_str = "";
464     std::string params_str = "";
465     pageRouterManager_->GetStateByIndex(info->index, name_str, path_str, params_str);
466     info->name = CopyStr(name_str);
467     info->path = CopyStr(path_str);
468     info->params = CopyStr(params_str);
469 }
470 
GetStateByUrl(const char * url)471 CJPageRouterAbstract::RouterStateList CJFrontendAbstract::GetStateByUrl(const char* url)
472 {
473     CJPageRouterAbstract::RouterStateList result;
474     std::vector<CJPageRouterAbstract::RouterState> states = pageRouterManager_->GetStateByUrl(url);
475     if (states.empty()) {
476         return result;
477     }
478     auto stateslist = new CJPageRouterAbstract::RouterState[states.size()];
479     size_t idx = 0;
480     for (auto state : states) {
481         stateslist[idx].index = state.index;
482         stateslist[idx].name = state.name;
483         stateslist[idx].path = state.path;
484         stateslist[idx].params = state.params;
485         idx++;
486     }
487     result.array = stateslist;
488     result.size = static_cast<int64_t>(states.size());
489     result.free = CJPageRouterAbstract::RouterStateListFree;
490     return result;
491 }
PushPageWithCallback(const std::string & url,const std::string & params,CJPageRouterAbstract::RouterMode & mode,std::function<void (int32_t)> && callback)492 void CJFrontendAbstract::PushPageWithCallback(const std::string& url, const std::string& params,
493     CJPageRouterAbstract::RouterMode& mode, std::function<void(int32_t)>&& callback)
494 {
495     pageRouterManager_->PushPageWithCallback({ url, mode, "", callback }, params);
496 }
497 
ReplacePageWithCallback(const std::string & url,const std::string & params,CJPageRouterAbstract::RouterMode & mode,std::function<void (int32_t)> && callback)498 void CJFrontendAbstract::ReplacePageWithCallback(const std::string& url, const std::string& params,
499     CJPageRouterAbstract::RouterMode& mode, std::function<void(int32_t)>&& callback)
500 {
501     pageRouterManager_->ReplacePageWithCallback({ url, mode, "", callback }, params);
502 }
503 
504 } // namespace OHOS::Ace
505