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_page_router_ng.h"
17
18 #include "securec.h"
19
20 #include "base/error/error_code.h"
21 #include "bridge/cj_frontend/frontend/cj_frontend_abstract.h"
22 #include "bridge/cj_frontend/frontend/cj_page_loader.h"
23 #include "bridge/cj_frontend/runtime/cj_runtime_delegate.h"
24 #include "core/components_ng/base/view_advanced_register.h"
25 #include "core/components_ng/pattern/stage/page_pattern.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27 #include "core/components/dialog/dialog_theme.h"
28
29 using namespace OHOS::Ace::NG;
30
31 namespace OHOS::Ace::Framework {
32 constexpr int PAGE_SIZE_TWO = 2;
33
UpdateCjPageLifeCycleFuncs(RefPtr<NG::PagePattern> pagePattern,OHOS::wptr<NativeView> weakView,RefPtr<NG::FrameNode> pageNode)34 void UpdateCjPageLifeCycleFuncs(
35 RefPtr<NG::PagePattern> pagePattern, OHOS::wptr<NativeView> weakView, RefPtr<NG::FrameNode> pageNode)
36 {
37 CHECK_NULL_VOID(pagePattern);
38 pagePattern->SetOnPageShow([weakView]() {
39 auto view = weakView.promote();
40 CHECK_NULL_VOID(view);
41 view->FireOnShow();
42 });
43 pagePattern->SetOnPageHide([weakView]() {
44 auto view = weakView.promote();
45 CHECK_NULL_VOID(view);
46 view->FireOnHide();
47 });
48 pagePattern->SetOnBackPressed([weakView]() {
49 auto view = weakView.promote();
50 CHECK_NULL_RETURN(view, false);
51 return view->FireOnBackPress();
52 });
53 pagePattern->SetPageTransitionFunc([weakView, weakPage = WeakPtr<NG::FrameNode>(pageNode)]() {
54 auto view = weakView.promote();
55 CHECK_NULL_VOID(view);
56 NG::ScopedViewStackProcessor scopedViewStackProcessor;
57 NG::ViewStackProcessor::GetInstance()->SetPageNode(weakPage.Upgrade());
58 view->FireOnTransition();
59 NG::ViewStackProcessor::GetInstance()->SetPageNode(nullptr);
60 });
61 }
62
LoadNativeViewNG(NativeView * view)63 bool LoadNativeViewNG(NativeView* view)
64 {
65 LOGI("LoadNativeView start");
66 auto currentObj = Container::Current();
67 if (!currentObj) {
68 LOGE("loadCJView fail, Container is null");
69 return false;
70 }
71 auto frontend = AceType::DynamicCast<CJFrontendAbstract>(currentObj->GetFrontend());
72 if (!frontend) {
73 LOGE("loadCJView fail, frontend is not CJFrontendAbstract");
74 return false;
75 }
76 auto pageRouterManager = AceType::DynamicCast<CJPageRouterNG>(frontend->GetPageRouterManager());
77 if (!pageRouterManager) {
78 LOGE("loadCJView fail, pageRouter not exist");
79 return false;
80 }
81 auto pageNode = pageRouterManager->GetCurrentPageNode();
82 if (!pageNode) {
83 LOGE("loadCJView fail, page node not exist");
84 return false;
85 }
86 Container::SetCurrentUsePartialUpdate(!view->IsFullUpdate());
87 if (!pageNode->GetChildren().empty()) {
88 LOGI("the page has view already, start cleanup");
89 auto oldChild = AceType::DynamicCast<NG::CustomNode>(pageNode->GetChildren().front());
90 if (oldChild) {
91 oldChild->Reset();
92 }
93 pageNode->Clean();
94 }
95 auto pageRootNode = AceType::DynamicCast<NG::UINode>(view->CreateUI());
96 if (!pageRootNode) {
97 LOGE("loadCJView fail, created rootNode is null");
98 return false;
99 }
100 pageRootNode->MountToParent(pageNode);
101 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
102 CHECK_NULL_RETURN(pagePattern, false);
103 OHOS::wptr<NativeView> weak = view;
104 view->SetRenderDoneCallback([pagePattern] { pagePattern->MarkRenderDone(); });
105 UpdateCjPageLifeCycleFuncs(pagePattern, weak, pageNode);
106 pageRouterManager->AddView(view->GetID());
107 LOGI("OHOSAceFrameworkNGLoadCJView end.");
108 return true;
109 }
110
111 namespace {
ExitToDesktop()112 void ExitToDesktop()
113 {
114 auto currentObj = Container::Current();
115 CHECK_NULL_VOID(currentObj);
116 auto taskExecutor = currentObj->GetTaskExecutor();
117 CHECK_NULL_VOID(taskExecutor);
118 taskExecutor->PostTask(
119 [] {
120 auto pipeline = NG::PipelineContext::GetCurrentContext();
121 CHECK_NULL_VOID(pipeline);
122 pipeline->Finish(false);
123 },
124 TaskExecutor::TaskType::UI, "CJExitToDesktop");
125 }
126
127 struct DialogStrings {
128 std::string cancel;
129 std::string confirm;
130 };
131
GetDialogStrings()132 DialogStrings GetDialogStrings()
133 {
134 DialogStrings strs = {"", ""};
135 auto context = NG::PipelineContext::GetCurrentContext();
136 CHECK_NULL_RETURN(context, strs);
137 auto dialogTheme = context->GetTheme<DialogTheme>();
138 CHECK_NULL_RETURN(dialogTheme, strs);
139
140 strs.cancel = dialogTheme->GetCancelText();
141 strs.confirm = dialogTheme->GetConfirmText();
142 return strs;
143 }
144 } // namespace
145
OnShowCurrent()146 void CJPageRouterNG::OnShowCurrent()
147 {
148 auto pageNode = GetCurrentPageNode();
149 if (!pageNode) {
150 LOGE("CJFrontendNG::OnShow no current page");
151 return;
152 }
153 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
154 if (!pagePattern) {
155 LOGE("CJFrontendNG::OnShow current page has no pattern");
156 return;
157 }
158 pagePattern->OnShow();
159 }
160
OnHideCurrent()161 void CJPageRouterNG::OnHideCurrent()
162 {
163 auto pageNode = GetCurrentPageNode();
164 if (!pageNode) {
165 LOGE("CJFrontendNG::OnHide no current page");
166 return;
167 }
168 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
169 if (!pagePattern) {
170 LOGE("CJFrontendNG::OnHide current page has no pattern");
171 return;
172 }
173 pagePattern->OnHide();
174 }
175
PopWithExitCheck()176 bool CJPageRouterNG::PopWithExitCheck()
177 {
178 auto pageNode = GetCurrentPageNode();
179 CHECK_NULL_RETURN(pageNode, false);
180 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
181 CHECK_NULL_RETURN(pagePattern, false);
182 if (pagePattern->OnBackPressed()) {
183 return true;
184 }
185 return Pop();
186 }
187
AllowPopLastPage()188 bool CJPageRouterNG::AllowPopLastPage()
189 {
190 auto currentPage = pageRouterStack_.back().Upgrade();
191 CHECK_NULL_RETURN(currentPage, true);
192 auto pagePattern = currentPage->GetPattern<PagePattern>();
193 CHECK_NULL_RETURN(pagePattern, true);
194 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
195 CHECK_NULL_RETURN(pageInfo, true);
196 if (pageInfo->GetAlertCallback()) {
197 auto pipelineContext = NG::PipelineContext::GetCurrentContext();
198 auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
199 CHECK_NULL_RETURN(overlayManager, true);
200 overlayManager->ShowDialog(
201 pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
202 return false;
203 }
204
205 return true;
206 }
207
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> callback)208 void CJPageRouterNG::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)> callback)
209 {
210 auto currentPage = pageRouterStack_.back().Upgrade();
211 CHECK_NULL_VOID(currentPage);
212 auto pagePattern = currentPage->GetPattern<PagePattern>();
213 CHECK_NULL_VOID(pagePattern);
214 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
215 CHECK_NULL_VOID(pageInfo);
216 ClearAlertCallback(pageInfo);
217
218 auto strs = GetDialogStrings();
219
220 DialogProperties dialogProperties = {
221 .content = message,
222 .autoCancel = false,
223 .buttons = { { .text = strs.cancel, .textColor = "" },
224 { .text = strs.confirm, .textColor = "" } },
225 .onSuccess =
226 [weak = AceType::WeakClaim(this), callback](int32_t successType, int32_t successIndex) {
227 LOGI("showDialog successType: %{public}d, successIndex: %{public}d", successType, successIndex);
228 if (!successType) {
229 callback(successIndex);
230 if (successIndex) {
231 auto router = weak.Upgrade();
232 CHECK_NULL_VOID(router);
233 if (router->ngBackIndex_ > 0) {
234 router->StartBackIndex(router->ngBackIndex_, router->backParam_);
235 } else {
236 router->StartBack(router->ngBackUri_, router->backParam_);
237 }
238 }
239 }
240 },
241 };
242
243 pageInfo->SetDialogProperties(dialogProperties);
244 pageInfo->SetAlertCallback(std::move(callback));
245 }
246
DisableAlertBeforeBackPage()247 void CJPageRouterNG::DisableAlertBeforeBackPage()
248 {
249 auto currentPage = pageRouterStack_.back().Upgrade();
250 CHECK_NULL_VOID(currentPage);
251 auto pagePattern = currentPage->GetPattern<PagePattern>();
252 CHECK_NULL_VOID(pagePattern);
253 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
254 CHECK_NULL_VOID(pageInfo);
255 ClearAlertCallback(pageInfo);
256 pageInfo->SetAlertCallback(nullptr);
257 }
258
ClearAlertCallback(const RefPtr<PageInfo> & pageInfo)259 void CJPageRouterNG::ClearAlertCallback(const RefPtr<PageInfo>& pageInfo)
260 {
261 if (pageInfo->GetAlertCallback()) {
262 // notify to clear js reference
263 auto alertCallback = pageInfo->GetAlertCallback();
264 alertCallback(static_cast<int32_t>(Framework::AlertState::RECOVERY));
265 pageInfo->SetAlertCallback(nullptr);
266 }
267 }
268
StartClean()269 void CJPageRouterNG::StartClean()
270 {
271 ProcessGuard guard(this);
272 if (pageRouterStack_.size() <= 1) {
273 LOGW("current page stack can not clean, %{public}d", static_cast<int32_t>(pageRouterStack_.size()));
274 return;
275 }
276 UpdateSrcPage();
277 std::list<WeakPtr<FrameNode>> temp;
278 std::swap(temp, pageRouterStack_);
279 pageRouterStack_.emplace_back(temp.back());
280 if (!OnCleanPageStack()) {
281 LOGE("fail to clean page");
282 std::swap(temp, pageRouterStack_);
283 }
284 }
285
StartPop()286 bool CJPageRouterNG::StartPop()
287 {
288 ProcessGuard guard(this);
289 if (pageRouterStack_.size() <= 1 || viewStack_.size() <= 1) {
290 // the last page.
291 return false;
292 }
293 UpdateSrcPage();
294 auto topNode = pageRouterStack_.back();
295 auto topView = viewStack_.back();
296 pageRouterStack_.pop_back();
297 viewStack_.pop_back();
298 if (!OnPopPage(true, true)) {
299 LOGE("fail to pop page.");
300 pageRouterStack_.emplace_back(topNode);
301 viewStack_.emplace_back(topView);
302 return false;
303 }
304 return true;
305 }
306
GetStackSize() const307 int32_t CJPageRouterNG::GetStackSize() const
308 {
309 return static_cast<int32_t>(pageRouterStack_.size());
310 }
311
GetParams() const312 std::string CJPageRouterNG::GetParams() const
313 {
314 if (pageRouterStack_.empty()) {
315 LOGE("fail to get page param due to stack is null");
316 return "";
317 }
318 auto pageNode = pageRouterStack_.back().Upgrade();
319 CHECK_NULL_RETURN(pageNode, "");
320 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
321 CHECK_NULL_RETURN(pagePattern, "");
322 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
323 CHECK_NULL_RETURN(pageInfo, "");
324 return pageInfo->GetPageParams();
325 }
326
GetCurrentPageUrl()327 std::string CJPageRouterNG::GetCurrentPageUrl()
328 {
329 if (pageRouterStack_.empty()) {
330 LOGW("current page stack is empty");
331 return "";
332 }
333 auto pageNode = pageRouterStack_.back().Upgrade();
334 CHECK_NULL_RETURN(pageNode, "");
335 auto pagePattern = pageNode->GetPattern<PagePattern>();
336 CHECK_NULL_RETURN(pagePattern, "");
337 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
338 CHECK_NULL_RETURN(entryPageInfo, "");
339 return entryPageInfo->GetPagePath();
340 }
341
FindPageInStack(const std::string & url)342 std::pair<int32_t, RefPtr<FrameNode>> CJPageRouterNG::FindPageInStack(const std::string& url)
343 {
344 auto iter = std::find_if(pageRouterStack_.rbegin(), pageRouterStack_.rend(), [url](const WeakPtr<FrameNode>& item) {
345 auto pageNode = item.Upgrade();
346 CHECK_NULL_RETURN(pageNode, false);
347 auto pagePattern = pageNode->GetPattern<PagePattern>();
348 CHECK_NULL_RETURN(pagePattern, false);
349 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
350 CHECK_NULL_RETURN(entryPageInfo, false);
351 return entryPageInfo->GetPageUrl() == url;
352 });
353 if (iter == pageRouterStack_.rend()) {
354 return { -1, nullptr };
355 }
356 // Returns to the forward position.
357 return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
358 }
359
StartPush(const RouterPageInfo & target,const std::string & params,RouterMode mode)360 void CJPageRouterNG::StartPush(const RouterPageInfo& target, const std::string& params, RouterMode mode)
361 {
362 ProcessGuard guard(this);
363 if (target.url.empty()) {
364 LOGE("router.Push uri is empty");
365 return;
366 }
367 UpdateSrcPage();
368 if (mode == RouterMode::SINGLE) {
369 auto pageInfo = FindPageInStack(target.url);
370 if (pageInfo.second) {
371 // find page in stack, move postion and update params.
372 MovePageToFront(pageInfo.first, pageInfo.second, params, false);
373 return;
374 }
375 }
376
377 LoadPage(GenerateNextPageId(), target, params);
378 }
379
StartReplace(const RouterPageInfo & target,const std::string & params,RouterMode mode)380 void CJPageRouterNG::StartReplace(const RouterPageInfo& target, const std::string& params, RouterMode mode)
381 {
382 ProcessGuard guard(this);
383 if (target.url.empty()) {
384 LOGE("router.Push uri is empty");
385 return;
386 }
387 UpdateSrcPage();
388 std::string url = target.url;
389
390 PopPage("", false, false);
391
392 if (mode == RouterMode::SINGLE) {
393 auto pageInfo = FindPageInStack(url);
394 if (pageInfo.second) {
395 // find page in stack, move postion and update params.
396 MovePageToFront(pageInfo.first, pageInfo.second, params, false, true, false);
397 return;
398 }
399 }
400
401 RouterPageInfo info { url };
402 LoadPage(GenerateNextPageId(), info, params, false, false, false);
403 }
404
StartBack(const RouterPageInfo & target,const std::string & params)405 void CJPageRouterNG::StartBack(const RouterPageInfo& target, const std::string& params)
406 {
407 if (target.url.empty()) {
408 std::string pagePath;
409 size_t pageRouteSize = pageRouterStack_.size();
410 if (pageRouteSize < PAGE_SIZE_TWO) {
411 LOGI("router stack is only one, back to desktop");
412 ExitToDesktop();
413 return;
414 }
415 UpdateSrcPage();
416 PopPage(params, true, true);
417 return;
418 }
419 UpdateSrcPage();
420 std::string url = target.url;
421 auto pageInfo = FindPageInStack(url);
422 if (pageInfo.second) {
423 // find page in stack, pop to specified index.
424 PopPageToIndex(pageInfo.first, params, true, true);
425 return;
426 }
427 LOGI("fail to find specified page to pop");
428 }
429
BackCheckAlert(const RouterPageInfo & target,const std::string & params)430 void CJPageRouterNG::BackCheckAlert(const RouterPageInfo& target, const std::string& params)
431 {
432 ProcessGuard guard(this);
433 if (pageRouterStack_.empty()) {
434 LOGI("page route stack is empty");
435 return;
436 }
437 auto currentPage = pageRouterStack_.back().Upgrade();
438 CHECK_NULL_VOID(currentPage);
439 auto pagePattern = currentPage->GetPattern<PagePattern>();
440 CHECK_NULL_VOID(pagePattern);
441 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) && pagePattern->GetPageInTransition()) {
442 LOGI("page is in transition");
443 return;
444 }
445
446 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
447 CHECK_NULL_VOID(pageInfo);
448 if (pageInfo->GetAlertCallback()) {
449 ngBackUri_ = target;
450 backParam_ = params;
451
452 auto pipelineContext = NG::PipelineContext::GetCurrentContext();
453 auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
454 CHECK_NULL_VOID(overlayManager);
455 overlayManager->ShowDialog(
456 pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
457 return;
458 }
459
460 StartBack(target, params);
461 }
462
LoadPage(int32_t pageId,const RouterPageInfo & target,const std::string & params,bool isRestore,bool needHideLast,bool needTransition)463 void CJPageRouterNG::LoadPage(int32_t pageId, const RouterPageInfo& target, const std::string& params, bool isRestore,
464 bool needHideLast, bool needTransition)
465 {
466 LOGI("PageRouterManager LoadPage[%{public}d]: %{public}s.", pageId, target.url.c_str());
467
468 auto pipeline = GetCurrentPipeline(false);
469 CHECK_NULL_VOID(pipeline);
470 if (!pipeline->GetStageManager()) {
471 LOGE("StageManager is null, waiting...");
472 auto frontend = frontend_.Upgrade();
473 CHECK_NULL_VOID(frontend);
474 auto taskExecutor = frontend->GetTaskExecutor();
475 CHECK_NULL_VOID(taskExecutor);
476 taskExecutor->PostTask(
477 [weak = WeakClaim(this), pageId, target, params, isRestore, needHideLast, needTransition] {
478 auto self = weak.Upgrade();
479 CHECK_NULL_VOID(self);
480 self->LoadPage(pageId, target, params, isRestore, needHideLast, needTransition);
481 },
482 TaskExecutor::TaskType::UI, "CJLoadPage");
483 return;
484 }
485
486 auto entryPageInfo = AceType::MakeRefPtr<NG::EntryPageInfo>(pageId, target.url, target.path, params);
487 auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
488 auto pageNode = NG::FrameNode::CreateFrameNode("page", ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
489 pageNode->SetHostPageId(pageId);
490
491 pageRouterStack_.emplace_back(pageNode);
492
493 if (!target.url.empty() && !CJRuntimeDelegate::GetInstance()->LoadAppEntry(target.url)) {
494 LOGE("Run CJ Page fail: %{public}s", target.url.c_str());
495 if (target.callback != nullptr) {
496 target.callback(ERROR_CODE_URI_ERROR);
497 }
498 pageRouterStack_.pop_back();
499 return;
500 }
501
502 if (!OnPageReady(pageNode, needHideLast, needTransition)) {
503 LOGE("fail to mount page");
504 pageRouterStack_.pop_back();
505 return;
506 }
507 LOGI("CJPageRouter LoadPage[%{public}d]: %{public}s. success", pageId, target.url.c_str());
508 }
509
MovePageToFront(int32_t index,const RefPtr<FrameNode> & pageNode,const std::string & params,bool needHideLast,bool forceShowCurrent,bool needTransition)510 void CJPageRouterNG::MovePageToFront(int32_t index, const RefPtr<FrameNode>& pageNode, const std::string& params,
511 bool needHideLast, bool forceShowCurrent, bool needTransition)
512 {
513 LOGD("MovePageToFront to index: %{public}d", index);
514 // update param first.
515 CHECK_NULL_VOID(pageNode);
516 auto pagePattern = pageNode->GetPattern<PagePattern>();
517 CHECK_NULL_VOID(pagePattern);
518 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
519 CHECK_NULL_VOID(pageInfo);
520
521 if (index == static_cast<int32_t>(pageRouterStack_.size() - 1)) {
522 LOGD("already on the top");
523 if (!params.empty()) {
524 pageInfo->ReplacePageParams(params);
525 }
526 if (forceShowCurrent) {
527 StageManager::FirePageShow(pageNode, PageTransitionType::NONE);
528 }
529 return;
530 }
531 CHECK_NULL_VOID(pageNode);
532 auto currentObj = Container::Current();
533 CHECK_NULL_VOID(currentObj);
534 auto pipeline = currentObj->GetPipelineContext();
535 CHECK_NULL_VOID(pipeline);
536 auto context = DynamicCast<NG::PipelineContext>(pipeline);
537 auto stageManager = context ? context->GetStageManager() : nullptr;
538 CHECK_NULL_VOID(stageManager);
539
540 // clean pageNode on index position.
541 auto iter = pageRouterStack_.begin();
542 std::advance(iter, index);
543 auto last = pageRouterStack_.erase(iter);
544 // push pageNode to top.
545 pageRouterStack_.emplace_back(pageNode);
546 std::string tempParam;
547 if (!params.empty()) {
548 tempParam = pageInfo->ReplacePageParams(params);
549 }
550 if (!stageManager->MovePageToFront(pageNode, needHideLast, needTransition)) {
551 LOGE("fail to move page to front");
552 // restore position and param.
553 pageRouterStack_.pop_back();
554 pageRouterStack_.insert(last, pageNode);
555 if (!tempParam.empty()) {
556 pageInfo->ReplacePageParams(tempParam);
557 }
558 }
559 }
560
PopPage(const std::string & params,bool needShowNext,bool needTransition)561 void CJPageRouterNG::PopPage(const std::string& params, bool needShowNext, bool needTransition)
562 {
563 if (pageRouterStack_.empty() || viewStack_.empty()) {
564 LOGE("page router stack size is illegal.");
565 return;
566 }
567 if (needShowNext && (pageRouterStack_.size() == 1)) {
568 LOGE("page router stack size is only one, can not show next.");
569 return;
570 }
571 auto topNode = pageRouterStack_.back();
572 auto topView = viewStack_.back();
573 pageRouterStack_.pop_back();
574 viewStack_.pop_back();
575 if (params.empty()) {
576 if (!OnPopPage(needShowNext, needTransition)) {
577 LOGE("fail to pop page.");
578 pageRouterStack_.emplace_back(topNode);
579 viewStack_.emplace_back(topView);
580 }
581 return;
582 }
583
584 // update param first.
585 auto nextNode = pageRouterStack_.back().Upgrade();
586 CHECK_NULL_VOID(nextNode);
587 auto pagePattern = nextNode->GetPattern<PagePattern>();
588 CHECK_NULL_VOID(pagePattern);
589 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
590 CHECK_NULL_VOID(pageInfo);
591 auto temp = pageInfo->ReplacePageParams(params);
592
593 if (OnPopPage(needShowNext, needTransition)) {
594 return;
595 }
596 LOGE("fail to pop page");
597 // restore stack and pageParam.
598 pageRouterStack_.emplace_back(topNode);
599 viewStack_.emplace_back(topView);
600 pageInfo->ReplacePageParams(temp);
601 }
602
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)603 void CJPageRouterNG::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
604 {
605 LOGD("PopPageToIndex to index: %{public}d", index);
606 std::list<WeakPtr<FrameNode>> temp;
607 std::swap(temp, pageRouterStack_);
608 auto iter = temp.begin();
609 for (int32_t current = 0; current <= index; ++current) {
610 pageRouterStack_.emplace_back(*iter);
611 iter++;
612 }
613 if (params.empty()) {
614 if (!OnPopPageToIndex(index, needShowNext, needTransition)) {
615 LOGE("fail to pop page to index.");
616 std::swap(temp, pageRouterStack_);
617 }
618 return;
619 }
620
621 // update param first.
622 auto nextNode = pageRouterStack_.back().Upgrade();
623 CHECK_NULL_VOID(nextNode);
624 auto pagePattern = nextNode->GetPattern<PagePattern>();
625 CHECK_NULL_VOID(pagePattern);
626 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
627 CHECK_NULL_VOID(pageInfo);
628 auto tempParam = pageInfo->ReplacePageParams(params);
629
630 if (OnPopPageToIndex(index, needShowNext, needTransition)) {
631 return;
632 }
633 LOGE("fail to pop page to index");
634 // restore stack and pageParam.
635 std::swap(temp, pageRouterStack_);
636 pageInfo->ReplacePageParams(tempParam);
637 }
638
GetCurrentPipeline(bool isCardRouter,uint64_t cardId)639 RefPtr<NG::PipelineContext> CJPageRouterNG::GetCurrentPipeline(bool isCardRouter, uint64_t cardId)
640 {
641 auto currentObj = Container::Current();
642 CHECK_NULL_RETURN(currentObj, nullptr);
643 RefPtr<PipelineBase> pipeline;
644 if (isCardRouter) {
645 auto weak = currentObj->GetCardPipeline(cardId);
646 pipeline = weak.Upgrade();
647 CHECK_NULL_RETURN(pipeline, nullptr);
648 } else {
649 pipeline = currentObj->GetPipelineContext();
650 CHECK_NULL_RETURN(pipeline, nullptr);
651 }
652
653 return DynamicCast<NG::PipelineContext>(pipeline);
654 }
655
OnPageReady(const RefPtr<FrameNode> & pageNode,bool needHideLast,bool needTransition,bool isCardRouter,uint64_t cardId)656 bool CJPageRouterNG::OnPageReady(
657 const RefPtr<FrameNode>& pageNode, bool needHideLast, bool needTransition, bool isCardRouter, uint64_t cardId)
658 {
659 auto context = GetCurrentPipeline(isCardRouter, cardId);
660 if (!context) {
661 LOGE("fail to push page due to pipeline context is not NG");
662 return false;
663 }
664 auto stageManager = context->GetStageManager();
665 if (!stageManager) {
666 LOGE("fail to push page due to stage manager is nullptr");
667 return false;
668 }
669 return stageManager->PushPage(pageNode, needHideLast, needTransition);
670 }
671
OnPopPage(bool needShowNext,bool needTransition)672 bool CJPageRouterNG::OnPopPage(bool needShowNext, bool needTransition)
673 {
674 auto currentObj = Container::Current();
675 CHECK_NULL_RETURN(currentObj, false);
676 auto pipeline = currentObj->GetPipelineContext();
677 CHECK_NULL_RETURN(pipeline, false);
678 auto context = DynamicCast<NG::PipelineContext>(pipeline);
679 auto stageManager = context ? context->GetStageManager() : nullptr;
680 if (stageManager) {
681 auto inPageNode = GetCurrentPageNode();
682 return stageManager->PopPage(inPageNode, needShowNext, needTransition);
683 }
684 LOGE("fail to pop page due to stage manager is nullptr");
685 return false;
686 }
687
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)688 bool CJPageRouterNG::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
689 {
690 auto currentObj = Container::Current();
691 CHECK_NULL_RETURN(currentObj, false);
692 auto pipeline = currentObj->GetPipelineContext();
693 CHECK_NULL_RETURN(pipeline, false);
694 auto context = DynamicCast<NG::PipelineContext>(pipeline);
695 auto stageManager = context ? context->GetStageManager() : nullptr;
696 if (stageManager) {
697 return stageManager->PopPageToIndex(index, needShowNext, needTransition);
698 }
699 LOGE("fail to pop page to index due to stage manager is nullptr");
700 return false;
701 }
702
OnCleanPageStack()703 bool CJPageRouterNG::OnCleanPageStack()
704 {
705 auto currentObj = Container::Current();
706 CHECK_NULL_RETURN(currentObj, false);
707 auto pipeline = currentObj->GetPipelineContext();
708 CHECK_NULL_RETURN(pipeline, false);
709 auto context = DynamicCast<NG::PipelineContext>(pipeline);
710 auto stageManager = context ? context->GetStageManager() : nullptr;
711 if (stageManager) {
712 return stageManager->CleanPageStack();
713 }
714 LOGE("fail to pop page to index due to stage manager is nullptr");
715 return false;
716 }
717
FlushReload()718 void CJPageRouterNG::FlushReload()
719 {
720 for (const auto& viewId : viewStack_) {
721 auto view = FFI::FFIData::GetData<NativeView>(viewId);
722 if (view == nullptr) {
723 continue;
724 }
725 view->MarkNeedUpdate();
726 }
727 }
728
UpdateSrcPage()729 void CJPageRouterNG::UpdateSrcPage()
730 {
731 auto currentObj = Container::Current();
732 CHECK_NULL_VOID(currentObj);
733 auto context = AceType::DynamicCast<NG::PipelineContext>(currentObj->GetPipelineContext());
734 auto stageManager = context->GetStageManager();
735 CHECK_NULL_VOID(stageManager);
736 stageManager->SetSrcPage(GetCurrentPageNode());
737 }
GetState(int32_t & index,std::string & name,std::string & path,std::string & params)738 void CJPageRouterNG::GetState(int32_t& index, std::string& name, std::string& path, std::string& params)
739 {
740 if (pageRouterStack_.empty()) {
741 LOGE("fail to get page state due to stack is null");
742 return;
743 }
744 index = static_cast<int32_t>(pageRouterStack_.size());
745 auto pageNode = pageRouterStack_.back().Upgrade();
746 CHECK_NULL_VOID(pageNode);
747 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
748 CHECK_NULL_VOID(pagePattern);
749 auto pageInfo = pagePattern->GetPageInfo();
750 CHECK_NULL_VOID(pageInfo);
751 name = pageInfo->GetPageUrl();
752 path = pageInfo->GetPagePath();
753 params = GetParams();
754 }
FindPageByIndex(int32_t & index)755 RefPtr<NG::FrameNode> CJPageRouterNG::FindPageByIndex(int32_t& index)
756 {
757 auto it = pageRouterStack_.begin();
758 std::advance(it, index - 1);
759 return it->Upgrade();
760 }
GetStateByIndex(int32_t & index,std::string & name,std::string & path,std::string & params)761 void CJPageRouterNG::GetStateByIndex(int32_t& index, std::string& name, std::string& path, std::string& params)
762 {
763 if (pageRouterStack_.empty() || static_cast<int32_t>(pageRouterStack_.size()) < index) {
764 LOGE("fail to get page state due to stack is null");
765 index = 0;
766 return;
767 }
768 auto pageNode = pageRouterStack_.back().Upgrade();
769 CHECK_NULL_VOID(pageNode);
770 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
771 CHECK_NULL_VOID(pagePattern);
772 auto pageInfo = pagePattern->GetPageInfo();
773 CHECK_NULL_VOID(pageInfo);
774 name = pageInfo->GetPageUrl();
775 path = pageInfo->GetPagePath();
776 params = GetParams();
777 }
CopyStr(const std::string & str)778 static char* CopyStr(const std::string& str)
779 {
780 char* newStr = new (std::nothrow) char[str.length() + 1];
781 if (newStr == nullptr) {
782 return nullptr;
783 }
784
785 int err = strcpy_s(newStr, str.length() + 1, str.c_str());
786 if (err != 0) {
787 delete[] newStr;
788 return nullptr;
789 }
790
791 return newStr;
792 }
GetStateByUrl(const std::string & url)793 std::vector<CJPageRouterAbstract::RouterState> CJPageRouterNG::GetStateByUrl(const std::string& url)
794 {
795 std::vector<CJPageRouterAbstract::RouterState> ret;
796 if (pageRouterStack_.empty()) {
797 LOGE("fail to get page state due to stack is null");
798 return ret;
799 }
800 int64_t index = 0;
801 for (auto it = pageRouterStack_.begin(); it != pageRouterStack_.end(); ++it) {
802 std::string name = "";
803 std::string path = "";
804 std::string params = "";
805 auto pageNode = it->Upgrade();
806 if (!pageNode)
807 return ret;
808 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
809 if (!pagePattern)
810 return ret;
811 auto pageInfo = pagePattern->GetPageInfo();
812 if (!pageInfo)
813 return ret;
814 name = pageInfo->GetPageUrl();
815 if (name == url) {
816 path = pageInfo->GetPagePath();
817 params = GetParams();
818 ret.push_back({ static_cast<int32_t>(index + 1), CopyStr(name), CopyStr(path), CopyStr(params) });
819 }
820 index++;
821 }
822 return ret;
823 }
StartBackIndex(int32_t & index,const std::string & params)824 void CJPageRouterNG::StartBackIndex(int32_t& index, const std::string& params)
825 {
826 std::string pagePath;
827 int32_t pageRouterSize = static_cast<int32_t>(pageRouterStack_.size());
828 if (pageRouterSize < index) {
829 return;
830 }
831 if (pageRouterSize < PAGE_SIZE_TWO) {
832 LOGI("router stack is only one, back to desktop");
833 ExitToDesktop();
834 return;
835 }
836 UpdateSrcPage();
837 PopPageToIndex(index, params, true, true);
838 }
839
StartPushPageWithCallback(const RouterPageInfo & target,const std::string & params)840 void CJPageRouterNG::StartPushPageWithCallback(const RouterPageInfo& target, const std::string& params)
841 {
842 ProcessGuard guard(this);
843 if (target.url.empty()) {
844 LOGE("router.Push uri is empty");
845 return;
846 }
847 UpdateSrcPage();
848 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
849 if (target.callback != nullptr) {
850 target.callback(ERROR_CODE_PAGE_STACK_FULL);
851 }
852 return;
853 }
854 if (target.routerMode == RouterMode::SINGLE) {
855 auto pageInfo = FindPageInStack(target.url);
856 if (pageInfo.second) {
857 // find page in stack, move postion and update params.
858 MovePageToFront(pageInfo.first, pageInfo.second, params, false);
859 return;
860 }
861 }
862
863 LoadPage(GenerateNextPageId(), target, params);
864 }
StartReplacePageWithCallback(const RouterPageInfo & target,const std::string & params)865 void CJPageRouterNG::StartReplacePageWithCallback(const RouterPageInfo& target, const std::string& params)
866 {
867 ProcessGuard guard(this);
868 if (target.url.empty()) {
869 LOGE("router.Push uri is empty");
870 return;
871 }
872 UpdateSrcPage();
873 std::string url = target.url;
874 PopPage("", false, false);
875
876 if (target.routerMode == RouterMode::SINGLE) {
877 auto pageInfo = FindPageInStack(url);
878 if (pageInfo.second) {
879 // find page in stack, move postion and update params.
880 MovePageToFront(pageInfo.first, pageInfo.second, params, false, true, true);
881 return;
882 }
883 }
884
885 LoadPage(GenerateNextPageId(), target, params, false, false, false);
886 }
BackCheckAlertIndex(int32_t index,const std::string & params)887 void CJPageRouterNG::BackCheckAlertIndex(int32_t index, const std::string& params)
888 {
889 ProcessGuard guard(this);
890 if (pageRouterStack_.empty()) {
891 LOGI("page route stack is empty");
892 return;
893 }
894 if (static_cast<int32_t>(pageRouterStack_.size()) < index) {
895 LOGI("index is invalid");
896 return;
897 }
898 auto currentPage = pageRouterStack_.back().Upgrade();
899 CHECK_NULL_VOID(currentPage);
900 auto pagePattern = currentPage->GetPattern<PagePattern>();
901 CHECK_NULL_VOID(pagePattern);
902 if (pagePattern->OnBackPressed()) {
903 return;
904 }
905
906 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
907 CHECK_NULL_VOID(pageInfo);
908 if (pageInfo->GetAlertCallback()) {
909 ngBackIndex_ = index;
910 backParam_ = params;
911
912 auto pipelineContext = NG::PipelineContext::GetCurrentContext();
913 auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
914 CHECK_NULL_VOID(overlayManager);
915 overlayManager->ShowDialog(
916 pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
917 return;
918 }
919
920 StartBackIndex(index, params);
921 }
922
923 } // namespace OHOS::Ace::Framework
924