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 "base/i18n/localization.h"
19 #include "bridge/cj_frontend/runtime/cj_runtime_delegate.h"
20 #include "bridge/cj_frontend/frontend/cj_frontend_abstract.h"
21 #include "bridge/cj_frontend/frontend/cj_page_loader.h"
22 #include "bridge/declarative_frontend/ng/entry_page_info.h"
23 #include "bridge/js_frontend/frontend_delegate.h"
24 #include "core/common/container.h"
25 #include "core/components_ng/pattern/stage/page_pattern.h"
26 #include "core/components_v2/inspector/inspector_constants.h"
27 #include "core/pipeline_ng/pipeline_context.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] {
105         pagePattern->MarkRenderDone();
106     });
107     UpdateCjPageLifeCycleFuncs(pagePattern, weak, pageNode);
108     pageRouterManager->AddView(view->GetID());
109     LOGI("OHOSAceFrameworkNGLoadCJView end.");
110     return true;
111 }
112 
113 namespace {
ExitToDesktop()114 void ExitToDesktop()
115 {
116     auto currentObj = Container::Current();
117     CHECK_NULL_VOID(currentObj);
118     auto taskExecutor = currentObj->GetTaskExecutor();
119     CHECK_NULL_VOID(taskExecutor);
120     taskExecutor->PostTask(
121         [] {
122             auto pipeline = NG::PipelineContext::GetCurrentContext();
123             CHECK_NULL_VOID(pipeline);
124             pipeline->Finish(false);
125         },
126         TaskExecutor::TaskType::UI, "CJExitToDesktop");
127 }
128 } // namespace
129 
OnShowCurrent()130 void CJPageRouterNG::OnShowCurrent()
131 {
132     auto pageNode = GetCurrentPageNode();
133     if (!pageNode) {
134         LOGE("CJFrontendNG::OnShow no current page");
135         return;
136     }
137     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
138     if (!pagePattern) {
139         LOGE("CJFrontendNG::OnShow current page has no pattern");
140         return;
141     }
142     pagePattern->OnShow();
143 }
144 
OnHideCurrent()145 void CJPageRouterNG::OnHideCurrent()
146 {
147     auto pageNode = GetCurrentPageNode();
148     if (!pageNode) {
149         LOGE("CJFrontendNG::OnHide no current page");
150         return;
151     }
152     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
153     if (!pagePattern) {
154         LOGE("CJFrontendNG::OnHide current page has no pattern");
155         return;
156     }
157     pagePattern->OnHide();
158 }
159 
PopWithExitCheck()160 bool CJPageRouterNG::PopWithExitCheck()
161 {
162     auto pageNode = GetCurrentPageNode();
163     CHECK_NULL_RETURN(pageNode, false);
164     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
165     CHECK_NULL_RETURN(pagePattern, false);
166     if (pagePattern->OnBackPressed()) {
167         return true;
168     }
169     return Pop();
170 }
171 
AllowPopLastPage()172 bool CJPageRouterNG::AllowPopLastPage()
173 {
174     auto currentPage = pageRouterStack_.back().Upgrade();
175     CHECK_NULL_RETURN(currentPage, true);
176     auto pagePattern = currentPage->GetPattern<PagePattern>();
177     CHECK_NULL_RETURN(pagePattern, true);
178     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
179     CHECK_NULL_RETURN(pageInfo, true);
180     if (pageInfo->GetAlertCallback()) {
181         auto pipelineContext = NG::PipelineContext::GetCurrentContext();
182         auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
183         CHECK_NULL_RETURN(overlayManager, true);
184         overlayManager->ShowDialog(
185             pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
186         return false;
187     }
188 
189     return true;
190 }
191 
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> callback)192 void CJPageRouterNG::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)> callback)
193 {
194     auto currentPage = pageRouterStack_.back().Upgrade();
195     CHECK_NULL_VOID(currentPage);
196     auto pagePattern = currentPage->GetPattern<PagePattern>();
197     CHECK_NULL_VOID(pagePattern);
198     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
199     CHECK_NULL_VOID(pageInfo);
200     ClearAlertCallback(pageInfo);
201 
202     DialogProperties dialogProperties = {
203         .content = message,
204         .autoCancel = false,
205         .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
206             { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
207         .onSuccess =
208             [weak = AceType::WeakClaim(this), callback](int32_t successType, int32_t successIndex) {
209                 LOGI("showDialog successType: %{public}d, successIndex: %{public}d", successType, successIndex);
210                 if (!successType) {
211                     callback(successIndex);
212                     if (successIndex) {
213                         auto router = weak.Upgrade();
214                         CHECK_NULL_VOID(router);
215                         router->StartBack(router->ngBackUri_, router->backParam_);
216                     }
217                 }
218             },
219     };
220 
221     pageInfo->SetDialogProperties(dialogProperties);
222     pageInfo->SetAlertCallback(std::move(callback));
223 }
224 
DisableAlertBeforeBackPage()225 void CJPageRouterNG::DisableAlertBeforeBackPage()
226 {
227     auto currentPage = pageRouterStack_.back().Upgrade();
228     CHECK_NULL_VOID(currentPage);
229     auto pagePattern = currentPage->GetPattern<PagePattern>();
230     CHECK_NULL_VOID(pagePattern);
231     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
232     CHECK_NULL_VOID(pageInfo);
233     ClearAlertCallback(pageInfo);
234     pageInfo->SetAlertCallback(nullptr);
235 }
236 
ClearAlertCallback(const RefPtr<PageInfo> & pageInfo)237 void CJPageRouterNG::ClearAlertCallback(const RefPtr<PageInfo>& pageInfo)
238 {
239     if (pageInfo->GetAlertCallback()) {
240         // notify to clear js reference
241         auto alertCallback = pageInfo->GetAlertCallback();
242         alertCallback(static_cast<int32_t>(Framework::AlertState::RECOVERY));
243         pageInfo->SetAlertCallback(nullptr);
244     }
245 }
246 
StartClean()247 void CJPageRouterNG::StartClean()
248 {
249     ProcessGuard guard(this);
250     if (pageRouterStack_.size() <= 1) {
251         LOGW("current page stack can not clean, %{public}d", static_cast<int32_t>(pageRouterStack_.size()));
252         return;
253     }
254     std::list<WeakPtr<FrameNode>> temp;
255     std::swap(temp, pageRouterStack_);
256     pageRouterStack_.emplace_back(temp.back());
257     if (!OnCleanPageStack()) {
258         LOGE("fail to clean page");
259         std::swap(temp, pageRouterStack_);
260     }
261 }
262 
StartPop()263 bool CJPageRouterNG::StartPop()
264 {
265     ProcessGuard guard(this);
266     if (pageRouterStack_.size() <= 1 || viewStack_.size() <= 1) {
267         // the last page.
268         return false;
269     }
270     auto topNode = pageRouterStack_.back();
271     auto topView = viewStack_.back();
272     pageRouterStack_.pop_back();
273     viewStack_.pop_back();
274     if (!OnPopPage(true, true)) {
275         LOGE("fail to pop page.");
276         pageRouterStack_.emplace_back(topNode);
277         viewStack_.emplace_back(topView);
278         return false;
279     }
280     return true;
281 }
282 
GetStackSize() const283 int32_t CJPageRouterNG::GetStackSize() const
284 {
285     return static_cast<int32_t>(pageRouterStack_.size());
286 }
287 
GetState(int32_t & index,std::string & name,std::string & path)288 void CJPageRouterNG::GetState(int32_t& index, std::string& name, std::string& path)
289 {
290     if (pageRouterStack_.empty()) {
291         LOGE("fail to get page state due to stack is null");
292         return;
293     }
294     index = static_cast<int32_t>(pageRouterStack_.size());
295     auto pageNode = pageRouterStack_.back().Upgrade();
296     CHECK_NULL_VOID(pageNode);
297     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
298     CHECK_NULL_VOID(pagePattern);
299     auto pageInfo = pagePattern->GetPageInfo();
300     CHECK_NULL_VOID(pageInfo);
301     name = pageInfo->GetPageUrl();
302     path = pageInfo->GetPagePath();
303 }
304 
GetParams() const305 std::string CJPageRouterNG::GetParams() const
306 {
307     if (pageRouterStack_.empty()) {
308         LOGE("fail to get page param due to stack is null");
309         return "";
310     }
311     auto pageNode = pageRouterStack_.back().Upgrade();
312     CHECK_NULL_RETURN(pageNode, "");
313     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
314     CHECK_NULL_RETURN(pagePattern, "");
315     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
316     CHECK_NULL_RETURN(pageInfo, "");
317     return pageInfo->GetPageParams();
318 }
319 
GetCurrentPageUrl()320 std::string CJPageRouterNG::GetCurrentPageUrl()
321 {
322     if (pageRouterStack_.empty()) {
323         LOGW("current page stack is empty");
324         return "";
325     }
326     auto pageNode = pageRouterStack_.back().Upgrade();
327     CHECK_NULL_RETURN(pageNode, "");
328     auto pagePattern = pageNode->GetPattern<PagePattern>();
329     CHECK_NULL_RETURN(pagePattern, "");
330     auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
331     CHECK_NULL_RETURN(entryPageInfo, "");
332     return entryPageInfo->GetPagePath();
333 }
334 
FindPageInStack(const std::string & url)335 std::pair<int32_t, RefPtr<FrameNode>> CJPageRouterNG::FindPageInStack(const std::string& url)
336 {
337     auto iter = std::find_if(pageRouterStack_.rbegin(), pageRouterStack_.rend(), [url](const WeakPtr<FrameNode>& item) {
338         auto pageNode = item.Upgrade();
339         CHECK_NULL_RETURN(pageNode, false);
340         auto pagePattern = pageNode->GetPattern<PagePattern>();
341         CHECK_NULL_RETURN(pagePattern, false);
342         auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
343         CHECK_NULL_RETURN(entryPageInfo, false);
344         return entryPageInfo->GetPageUrl() == url;
345     });
346     if (iter == pageRouterStack_.rend()) {
347         return { -1, nullptr };
348     }
349     // Returns to the forward position.
350     return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
351 }
352 
StartPush(const RouterPageInfo & target,const std::string & params,RouterMode mode)353 void CJPageRouterNG::StartPush(const RouterPageInfo& target, const std::string& params, RouterMode mode)
354 {
355     ProcessGuard guard(this);
356     if (target.url.empty()) {
357         LOGE("router.Push uri is empty");
358         return;
359     }
360 
361     if (mode == RouterMode::SINGLE) {
362         auto pageInfo = FindPageInStack(target.url);
363         if (pageInfo.second) {
364             // find page in stack, move postion and update params.
365             MovePageToFront(pageInfo.first, pageInfo.second, params, false);
366             return;
367         }
368     }
369 
370     LoadPage(GenerateNextPageId(), target, params);
371 }
372 
StartReplace(const RouterPageInfo & target,const std::string & params,RouterMode mode)373 void CJPageRouterNG::StartReplace(const RouterPageInfo& target, const std::string& params, RouterMode mode)
374 {
375     ProcessGuard guard(this);
376     if (target.url.empty()) {
377         LOGE("router.Push uri is empty");
378         return;
379     }
380     std::string url = target.url;
381 
382     PopPage("", false, false);
383 
384     if (mode == RouterMode::SINGLE) {
385         auto pageInfo = FindPageInStack(url);
386         if (pageInfo.second) {
387             // find page in stack, move postion and update params.
388             MovePageToFront(pageInfo.first, pageInfo.second, params, false, true, false);
389             return;
390         }
391     }
392 
393     RouterPageInfo info { url };
394     LoadPage(GenerateNextPageId(), info, params, false, false, false);
395 }
396 
StartBack(const RouterPageInfo & target,const std::string & params)397 void CJPageRouterNG::StartBack(const RouterPageInfo& target, const std::string& params)
398 {
399     if (target.url.empty()) {
400         std::string pagePath;
401         size_t pageRouteSize = pageRouterStack_.size();
402         if (pageRouteSize < PAGE_SIZE_TWO) {
403             LOGI("router stack is only one, back to desktop");
404             ExitToDesktop();
405             return;
406         }
407         PopPage(params, true, true);
408         return;
409     }
410     std::string url = target.url;
411     auto pageInfo = FindPageInStack(url);
412     if (pageInfo.second) {
413         // find page in stack, pop to specified index.
414         PopPageToIndex(pageInfo.first, params, true, true);
415         return;
416     }
417     LOGI("fail to find specified page to pop");
418 }
419 
BackCheckAlert(const RouterPageInfo & target,const std::string & params)420 void CJPageRouterNG::BackCheckAlert(const RouterPageInfo& target, const std::string& params)
421 {
422     ProcessGuard guard(this);
423     if (pageRouterStack_.empty()) {
424         LOGI("page route stack is empty");
425         return;
426     }
427     auto currentPage = pageRouterStack_.back().Upgrade();
428     CHECK_NULL_VOID(currentPage);
429     auto pagePattern = currentPage->GetPattern<PagePattern>();
430     CHECK_NULL_VOID(pagePattern);
431     if (pagePattern->OnBackPressed()) {
432         return;
433     }
434 
435     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
436     CHECK_NULL_VOID(pageInfo);
437     if (pageInfo->GetAlertCallback()) {
438         ngBackUri_ = target;
439         backParam_ = params;
440 
441         auto pipelineContext = NG::PipelineContext::GetCurrentContext();
442         auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
443         CHECK_NULL_VOID(overlayManager);
444         overlayManager->ShowDialog(
445             pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
446         return;
447     }
448 
449     StartBack(target, params);
450 }
451 
LoadPage(int32_t pageId,const RouterPageInfo & target,const std::string & params,bool isRestore,bool needHideLast,bool needTransition)452 void CJPageRouterNG::LoadPage(int32_t pageId, const RouterPageInfo& target, const std::string& params, bool isRestore,
453     bool needHideLast, bool needTransition)
454 {
455     LOGI("PageRouterManager LoadPage[%{public}d]: %{public}s.", pageId, target.url.c_str());
456 
457     auto pipeline = GetCurrentPipeline(false);
458     CHECK_NULL_VOID(pipeline);
459     if (!pipeline->GetStageManager()) {
460         LOGE("StageManager is null, waiting...");
461         auto frontend = frontend_.Upgrade();
462         CHECK_NULL_VOID(frontend);
463         auto taskExecutor = frontend->GetTaskExecutor();
464         CHECK_NULL_VOID(taskExecutor);
465         taskExecutor->PostTask([weak = WeakClaim(this), pageId, target, params, isRestore,
466             needHideLast, needTransition] {
467                 auto self = weak.Upgrade();
468                 CHECK_NULL_VOID(self);
469                 self->LoadPage(pageId, target, params, isRestore, needHideLast, needTransition);
470             }, TaskExecutor::TaskType::UI, "CJLoadPage");
471         return;
472     }
473 
474     auto entryPageInfo = AceType::MakeRefPtr<NG::EntryPageInfo>(pageId, target.url, target.path, params);
475     auto pagePattern = AceType::MakeRefPtr<NG::PagePattern>(entryPageInfo);
476     auto pageNode =
477         NG::FrameNode::CreateFrameNode("page", ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
478     pageNode->SetHostPageId(pageId);
479 
480     pageRouterStack_.emplace_back(pageNode);
481 
482     if (!CJRuntimeDelegate::GetInstance()->LoadAppEntry(target.url)) {
483         LOGE("Run CJ Page fail: %{public}s", target.url.c_str());
484         pageRouterStack_.pop_back();
485         return;
486     }
487 
488     if (!OnPageReady(pageNode, needHideLast, needTransition)) {
489         LOGE("fail to mount page");
490         pageRouterStack_.pop_back();
491         return;
492     }
493     LOGI("CJPageRouter LoadPage[%{public}d]: %{public}s. success", pageId, target.url.c_str());
494 }
495 
MovePageToFront(int32_t index,const RefPtr<FrameNode> & pageNode,const std::string & params,bool needHideLast,bool forceShowCurrent,bool needTransition)496 void CJPageRouterNG::MovePageToFront(int32_t index, const RefPtr<FrameNode>& pageNode, const std::string& params,
497     bool needHideLast, bool forceShowCurrent, bool needTransition)
498 {
499     LOGD("MovePageToFront to index: %{public}d", index);
500     // update param first.
501     CHECK_NULL_VOID(pageNode);
502     auto pagePattern = pageNode->GetPattern<PagePattern>();
503     CHECK_NULL_VOID(pagePattern);
504     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
505     CHECK_NULL_VOID(pageInfo);
506 
507     if (index == static_cast<int32_t>(pageRouterStack_.size() - 1)) {
508         LOGD("already on the top");
509         if (!params.empty()) {
510             pageInfo->ReplacePageParams(params);
511         }
512         if (forceShowCurrent) {
513             StageManager::FirePageShow(pageNode, PageTransitionType::NONE);
514         }
515         return;
516     }
517     CHECK_NULL_VOID(pageNode);
518     auto currentObj = Container::Current();
519     CHECK_NULL_VOID(currentObj);
520     auto pipeline = currentObj->GetPipelineContext();
521     CHECK_NULL_VOID(pipeline);
522     auto context = DynamicCast<NG::PipelineContext>(pipeline);
523     auto stageManager = context ? context->GetStageManager() : nullptr;
524     CHECK_NULL_VOID(stageManager);
525 
526     // clean pageNode on index position.
527     auto iter = pageRouterStack_.begin();
528     std::advance(iter, index);
529     auto last = pageRouterStack_.erase(iter);
530     // push pageNode to top.
531     pageRouterStack_.emplace_back(pageNode);
532     std::string tempParam;
533     if (!params.empty()) {
534         tempParam = pageInfo->ReplacePageParams(params);
535     }
536     if (!stageManager->MovePageToFront(pageNode, needHideLast, needTransition)) {
537         LOGE("fail to move page to front");
538         // restore position and param.
539         pageRouterStack_.pop_back();
540         pageRouterStack_.insert(last, pageNode);
541         if (!tempParam.empty()) {
542             pageInfo->ReplacePageParams(tempParam);
543         }
544     }
545 }
546 
PopPage(const std::string & params,bool needShowNext,bool needTransition)547 void CJPageRouterNG::PopPage(const std::string& params, bool needShowNext, bool needTransition)
548 {
549     if (pageRouterStack_.empty() || viewStack_.empty()) {
550         LOGE("page router stack size is illegal.");
551         return;
552     }
553     if (needShowNext && (pageRouterStack_.size() == 1)) {
554         LOGE("page router stack size is only one, can not show next.");
555         return;
556     }
557     auto topNode = pageRouterStack_.back();
558     auto topView = viewStack_.back();
559     pageRouterStack_.pop_back();
560     viewStack_.pop_back();
561     if (params.empty()) {
562         if (!OnPopPage(needShowNext, needTransition)) {
563             LOGE("fail to pop page.");
564             pageRouterStack_.emplace_back(topNode);
565             viewStack_.emplace_back(topView);
566         }
567         return;
568     }
569 
570     // update param first.
571     auto nextNode = pageRouterStack_.back().Upgrade();
572     CHECK_NULL_VOID(nextNode);
573     auto pagePattern = nextNode->GetPattern<PagePattern>();
574     CHECK_NULL_VOID(pagePattern);
575     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
576     CHECK_NULL_VOID(pageInfo);
577     auto temp = pageInfo->ReplacePageParams(params);
578 
579     if (OnPopPage(needShowNext, needTransition)) {
580         return;
581     }
582     LOGE("fail to pop page");
583     // restore stack and pageParam.
584     pageRouterStack_.emplace_back(topNode);
585     viewStack_.emplace_back(topView);
586     pageInfo->ReplacePageParams(temp);
587 }
588 
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)589 void CJPageRouterNG::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
590 {
591     LOGD("PopPageToIndex to index: %{public}d", index);
592     std::list<WeakPtr<FrameNode>> temp;
593     std::swap(temp, pageRouterStack_);
594     auto iter = temp.begin();
595     for (int32_t current = 0; current <= index; ++current) {
596         pageRouterStack_.emplace_back(*iter);
597         iter++;
598     }
599     if (params.empty()) {
600         if (!OnPopPageToIndex(index, needShowNext, needTransition)) {
601             LOGE("fail to pop page to index.");
602             std::swap(temp, pageRouterStack_);
603         }
604         return;
605     }
606 
607     // update param first.
608     auto nextNode = pageRouterStack_.back().Upgrade();
609     CHECK_NULL_VOID(nextNode);
610     auto pagePattern = nextNode->GetPattern<PagePattern>();
611     CHECK_NULL_VOID(pagePattern);
612     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
613     CHECK_NULL_VOID(pageInfo);
614     auto tempParam = pageInfo->ReplacePageParams(params);
615 
616     if (OnPopPageToIndex(index, needShowNext, needTransition)) {
617         return;
618     }
619     LOGE("fail to pop page to index");
620     // restore stack and pageParam.
621     std::swap(temp, pageRouterStack_);
622     pageInfo->ReplacePageParams(tempParam);
623 }
624 
GetCurrentPipeline(bool isCardRouter,uint64_t cardId)625 RefPtr<NG::PipelineContext> CJPageRouterNG::GetCurrentPipeline(bool isCardRouter, uint64_t cardId)
626 {
627     auto currentObj = Container::Current();
628     CHECK_NULL_RETURN(currentObj, nullptr);
629     RefPtr<PipelineBase> pipeline;
630     if (isCardRouter) {
631         auto weak = currentObj->GetCardPipeline(cardId);
632         pipeline = weak.Upgrade();
633         CHECK_NULL_RETURN(pipeline, nullptr);
634     } else {
635         pipeline = currentObj->GetPipelineContext();
636         CHECK_NULL_RETURN(pipeline, nullptr);
637     }
638 
639     return DynamicCast<NG::PipelineContext>(pipeline);
640 }
641 
OnPageReady(const RefPtr<FrameNode> & pageNode,bool needHideLast,bool needTransition,bool isCardRouter,uint64_t cardId)642 bool CJPageRouterNG::OnPageReady(
643     const RefPtr<FrameNode>& pageNode, bool needHideLast, bool needTransition, bool isCardRouter, uint64_t cardId)
644 {
645     auto context = GetCurrentPipeline(isCardRouter, cardId);
646     if (!context) {
647         LOGE("fail to push page due to pipeline context is not NG");
648         return false;
649     }
650     auto stageManager = context->GetStageManager();
651     if (!stageManager) {
652         LOGE("fail to push page due to stage manager is nullptr");
653         return false;
654     }
655     return stageManager->PushPage(pageNode, needHideLast, needTransition);
656 }
657 
OnPopPage(bool needShowNext,bool needTransition)658 bool CJPageRouterNG::OnPopPage(bool needShowNext, bool needTransition)
659 {
660     auto currentObj = Container::Current();
661     CHECK_NULL_RETURN(currentObj, false);
662     auto pipeline = currentObj->GetPipelineContext();
663     CHECK_NULL_RETURN(pipeline, false);
664     auto context = DynamicCast<NG::PipelineContext>(pipeline);
665     auto stageManager = context ? context->GetStageManager() : nullptr;
666     if (stageManager) {
667         return stageManager->PopPage(needShowNext, needTransition);
668     }
669     LOGE("fail to pop page due to stage manager is nullptr");
670     return false;
671 }
672 
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)673 bool CJPageRouterNG::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
674 {
675     auto currentObj = Container::Current();
676     CHECK_NULL_RETURN(currentObj, false);
677     auto pipeline = currentObj->GetPipelineContext();
678     CHECK_NULL_RETURN(pipeline, false);
679     auto context = DynamicCast<NG::PipelineContext>(pipeline);
680     auto stageManager = context ? context->GetStageManager() : nullptr;
681     if (stageManager) {
682         return stageManager->PopPageToIndex(index, needShowNext, needTransition);
683     }
684     LOGE("fail to pop page to index due to stage manager is nullptr");
685     return false;
686 }
687 
OnCleanPageStack()688 bool CJPageRouterNG::OnCleanPageStack()
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->CleanPageStack();
698     }
699     LOGE("fail to pop page to index due to stage manager is nullptr");
700     return false;
701 }
702 
FlushReload()703 void CJPageRouterNG::FlushReload()
704 {
705     for (const auto& viewId : viewStack_) {
706         auto view = FFI::FFIData::GetData<NativeView>(viewId);
707         if (view == nullptr) {
708             continue;
709         }
710         view->MarkNeedUpdate();
711     }
712 }
713 } // namespace OHOS::Ace::Framework
714