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