• 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_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