1 /*
2 * Copyright (c) 2022 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 "frameworks/bridge/declarative_frontend/ng/page_router_manager.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <iterator>
21 #include <string>
22
23 #include "base/i18n/localization.h"
24 #include "base/memory/referenced.h"
25 #include "base/ressched/ressched_report.h"
26 #include "base/utils/utils.h"
27 #include "bridge/common/utils/source_map.h"
28 #include "bridge/common/utils/utils.h"
29 #include "bridge/declarative_frontend/ng/entry_page_info.h"
30 #include "bridge/js_frontend/frontend_delegate.h"
31 #include "core/common/container.h"
32 #include "core/common/thread_checker.h"
33 #include "core/components_ng/base/frame_node.h"
34 #include "core/components_ng/pattern/stage/page_pattern.h"
35 #include "core/components_ng/pattern/stage/stage_manager.h"
36 #include "core/components_v2/inspector/inspector_constants.h"
37 #include "core/pipeline/base/element_register.h"
38 #include "core/pipeline_ng/pipeline_context.h"
39
40 namespace OHOS::Ace::NG {
41
42 namespace {
43
44 constexpr int32_t MAX_ROUTER_STACK_SIZE = 32;
45
ExitToDesktop()46 void ExitToDesktop()
47 {
48 auto container = Container::Current();
49 CHECK_NULL_VOID(container);
50 auto taskExecutor = container->GetTaskExecutor();
51 CHECK_NULL_VOID(taskExecutor);
52 taskExecutor->PostTask(
53 [] {
54 auto pipeline = PipelineContext::GetCurrentContext();
55 CHECK_NULL_VOID(pipeline);
56 AccessibilityEvent event;
57 event.type = AccessibilityEventType::PAGE_CHANGE;
58 pipeline->SendEventToAccessibility(event);
59 pipeline->Finish(false);
60 },
61 TaskExecutor::TaskType::UI);
62 }
63
64 } // namespace
65
LoadOhmUrl(const RouterPageInfo & target)66 void PageRouterManager::LoadOhmUrl(const RouterPageInfo& target)
67 {
68 RouterPageInfo info = target;
69 info.path = info.url + ".js";
70 LOGD("router.Push pagePath = %{private}s", info.url.c_str());
71 RouterOptScope scope(this);
72 LoadPage(GenerateNextPageId(), info);
73 }
74
RunPage(const std::string & url,const std::string & params)75 void PageRouterManager::RunPage(const std::string& url, const std::string& params)
76 {
77 ACE_SCOPED_TRACE("PageRouterManager::RunPage");
78 CHECK_RUN_ON(JS);
79 RouterPageInfo info { url, params };
80 #if !defined(PREVIEW)
81 if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
82 auto container = Container::Current();
83 CHECK_NULL_VOID(container);
84 auto pageUrlChecker = container->GetPageUrlChecker();
85 CHECK_NULL_VOID(pageUrlChecker);
86 auto instanceId = container->GetInstanceId();
87 auto taskExecutor = container->GetTaskExecutor();
88 CHECK_NULL_VOID(taskExecutor);
89 auto callback = [weak = AceType::WeakClaim(this), info, taskExecutor, instanceId]() {
90 ContainerScope scope(instanceId);
91 auto pageRouterManager = weak.Upgrade();
92 CHECK_NULL_VOID(pageRouterManager);
93 taskExecutor->PostTask(
94 [pageRouterManager, info]() { pageRouterManager->LoadOhmUrl(info); }, TaskExecutor::TaskType::JS);
95 };
96
97 auto silentInstallErrorCallBack = [taskExecutor, instanceId](int32_t errorCode, const std::string& errorMsg) {
98 ContainerScope scope(instanceId);
99 taskExecutor->PostTask(
100 [errorCode, errorMsg]() {
101 LOGE("Run page error = %{public}d, errorMsg = %{public}s", errorCode, errorMsg.c_str());
102 },
103 TaskExecutor::TaskType::JS);
104 };
105
106 pageUrlChecker->LoadPageUrl(url, callback, silentInstallErrorCallBack);
107 return;
108 }
109 #endif
110 if (!info.url.empty()) {
111 info.path = manifestParser_->GetRouter()->GetPagePath(url);
112 if (info.path.empty()) {
113 LOGE("[Engine Log] this uri not support in route push.");
114 return;
115 }
116 } else {
117 info.path = manifestParser_->GetRouter()->GetEntry();
118 info.url = manifestParser_->GetRouter()->GetEntry("");
119 }
120 LOGD("router.Push pagePath = %{private}s", info.url.c_str());
121 RouterOptScope scope(this);
122 LoadPage(GenerateNextPageId(), info);
123 }
124
RunCard(const std::string & url,const std::string & params,int64_t cardId)125 void PageRouterManager::RunCard(const std::string& url, const std::string& params, int64_t cardId)
126 {
127 CHECK_RUN_ON(JS);
128 RouterPageInfo info { url };
129 #ifndef PREVIEW
130 if (!info.url.empty()) {
131 info.path = manifestParser_->GetRouter()->GetPagePath(url);
132 } else {
133 info.path = manifestParser_->GetRouter()->GetEntry();
134 info.url = manifestParser_->GetRouter()->GetEntry("");
135 }
136 #endif
137 LoadCard(0, info, params, cardId);
138 }
139
Push(const RouterPageInfo & target)140 void PageRouterManager::Push(const RouterPageInfo& target)
141 {
142 CHECK_RUN_ON(JS);
143 if (inRouterOpt_) {
144 LOGI("in router opt, post push router task");
145 auto context = PipelineContext::GetCurrentContext();
146 CHECK_NULL_VOID(context);
147 context->PostAsyncEvent(
148 [weak = WeakClaim(this), target]() {
149 auto router = weak.Upgrade();
150 CHECK_NULL_VOID(router);
151 router->Push(target);
152 },
153 TaskExecutor::TaskType::JS);
154 return;
155 }
156 RouterOptScope scope(this);
157 StartPush(target);
158 }
159
PushNamedRoute(const RouterPageInfo & target)160 void PageRouterManager::PushNamedRoute(const RouterPageInfo& target)
161 {
162 CHECK_RUN_ON(JS);
163 if (inRouterOpt_) {
164 LOGI("in router opt, post push named route router task");
165 auto context = PipelineContext::GetCurrentContext();
166 CHECK_NULL_VOID(context);
167 context->PostAsyncEvent(
168 [weak = WeakClaim(this), target]() {
169 auto router = weak.Upgrade();
170 CHECK_NULL_VOID(router);
171 router->PushNamedRoute(target);
172 },
173 TaskExecutor::TaskType::JS);
174 return;
175 }
176 RouterOptScope scope(this);
177 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
178 LOGE("router stack size is larger than max size 32.");
179 if (target.errorCallback != nullptr) {
180 target.errorCallback("The pages are pushed too much.", Framework::ERROR_CODE_PAGE_STACK_FULL);
181 }
182 return;
183 }
184 CleanPageOverlay();
185 if (target.routerMode == RouterMode::SINGLE) {
186 auto pageInfo = FindPageInStack(target.url);
187 if (pageInfo.second) {
188 // find page in stack, move postion and update params.
189 MovePageToFront(pageInfo.first, pageInfo.second, target, false);
190 return;
191 }
192 }
193 RouterPageInfo info = target;
194 info.isNamedRouterMode = true;
195 LoadPage(GenerateNextPageId(), info);
196 }
197
Replace(const RouterPageInfo & target)198 void PageRouterManager::Replace(const RouterPageInfo& target)
199 {
200 CHECK_RUN_ON(JS);
201 if (inRouterOpt_) {
202 LOGI("in router opt, post replace router task");
203 auto context = PipelineContext::GetCurrentContext();
204 CHECK_NULL_VOID(context);
205 context->PostAsyncEvent(
206 [weak = WeakClaim(this), target]() {
207 auto router = weak.Upgrade();
208 CHECK_NULL_VOID(router);
209 router->Replace(target);
210 },
211 TaskExecutor::TaskType::JS);
212 return;
213 }
214 RouterOptScope scope(this);
215 StartReplace(target);
216 }
217
ReplaceNamedRoute(const RouterPageInfo & target)218 void PageRouterManager::ReplaceNamedRoute(const RouterPageInfo& target)
219 {
220 CHECK_RUN_ON(JS);
221 if (inRouterOpt_) {
222 LOGI("in router opt, post replace named route router task");
223 auto context = PipelineContext::GetCurrentContext();
224 CHECK_NULL_VOID(context);
225 context->PostAsyncEvent(
226 [weak = WeakClaim(this), target]() {
227 auto router = weak.Upgrade();
228 CHECK_NULL_VOID(router);
229 router->ReplaceNamedRoute(target);
230 },
231 TaskExecutor::TaskType::JS);
232 return;
233 }
234 RouterOptScope scope(this);
235 CleanPageOverlay();
236 PopPage("", false, false);
237 if (target.routerMode == RouterMode::SINGLE) {
238 auto pageInfo = FindPageInStack(target.url);
239 if (pageInfo.second) {
240 // find page in stack, move postion and update params.
241 MovePageToFront(pageInfo.first, pageInfo.second, target, false);
242 return;
243 }
244 }
245 RouterPageInfo info = target;
246 info.isNamedRouterMode = true;
247 LoadPage(GenerateNextPageId(), info, false, false);
248 }
249
BackWithTarget(const RouterPageInfo & target)250 void PageRouterManager::BackWithTarget(const RouterPageInfo& target)
251 {
252 CHECK_RUN_ON(JS);
253 LOGI("router.Back path = %{private}s", target.url.c_str());
254 if (inRouterOpt_) {
255 LOGI("in router opt, post back router task");
256 auto context = PipelineContext::GetCurrentContext();
257 CHECK_NULL_VOID(context);
258 context->PostAsyncEvent(
259 [weak = WeakClaim(this), target]() {
260 auto router = weak.Upgrade();
261 CHECK_NULL_VOID(router);
262 router->BackWithTarget(target);
263 },
264 TaskExecutor::TaskType::JS);
265 return;
266 }
267 RouterOptScope scope(this);
268 BackCheckAlert(target);
269 }
270
Clear()271 void PageRouterManager::Clear()
272 {
273 CHECK_RUN_ON(JS);
274 if (inRouterOpt_) {
275 LOGI("in router opt, post clear router task");
276 auto context = PipelineContext::GetCurrentContext();
277 CHECK_NULL_VOID(context);
278 context->PostAsyncEvent(
279 [weak = WeakClaim(this)]() {
280 auto router = weak.Upgrade();
281 CHECK_NULL_VOID(router);
282 router->Clear();
283 },
284 TaskExecutor::TaskType::JS);
285 return;
286 }
287 RouterOptScope scope(this);
288 StartClean();
289 }
290
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)291 void PageRouterManager::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)>&& callback)
292 {
293 auto currentPage = pageRouterStack_.back().Upgrade();
294 CHECK_NULL_VOID(currentPage);
295 auto pagePattern = currentPage->GetPattern<PagePattern>();
296 CHECK_NULL_VOID(pagePattern);
297 auto pageInfo = pagePattern->GetPageInfo();
298 CHECK_NULL_VOID(pageInfo);
299
300 DialogProperties dialogProperties = {
301 .content = message,
302 .autoCancel = false,
303 .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
304 { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
305 .onSuccess =
306 [weak = AceType::WeakClaim(this), weakPageInfo = AceType::WeakClaim(AceType::RawPtr(pageInfo))](
307 int32_t successType, int32_t successIndex) {
308 LOGI("showDialog successType: %{public}d, successIndex: %{public}d", successType, successIndex);
309 auto pageInfo = weakPageInfo.Upgrade();
310 if (pageInfo && pageInfo->GetAlertCallback() && !successType) {
311 pageInfo->GetAlertCallback()(successIndex);
312 if (successIndex) {
313 auto router = weak.Upgrade();
314 CHECK_NULL_VOID(router);
315 router->StartBack(router->ngBackTarget_);
316 }
317 }
318 },
319 };
320
321 pageInfo->SetDialogProperties(dialogProperties);
322 pageInfo->SetAlertCallback(std::move(callback));
323 }
324
DisableAlertBeforeBackPage()325 void PageRouterManager::DisableAlertBeforeBackPage()
326 {
327 auto currentPage = pageRouterStack_.back().Upgrade();
328 CHECK_NULL_VOID(currentPage);
329 auto pagePattern = currentPage->GetPattern<PagePattern>();
330 CHECK_NULL_VOID(pagePattern);
331 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
332 CHECK_NULL_VOID(pageInfo);
333 pageInfo->SetAlertCallback(nullptr);
334 }
335
StartClean()336 void PageRouterManager::StartClean()
337 {
338 if (pageRouterStack_.size() <= 1) {
339 LOGW("current page stack can not clean, %{public}d", static_cast<int32_t>(pageRouterStack_.size()));
340 return;
341 }
342 std::list<WeakPtr<FrameNode>> temp;
343 std::swap(temp, pageRouterStack_);
344 pageRouterStack_.emplace_back(temp.back());
345 if (!OnCleanPageStack()) {
346 LOGE("fail to clean page");
347 std::swap(temp, pageRouterStack_);
348 }
349 }
350
Pop()351 bool PageRouterManager::Pop()
352 {
353 CHECK_RUN_ON(JS);
354 LOGI("router pop be called");
355 if (inRouterOpt_) {
356 LOGE("in router opt, post Pop router task failed");
357 return false;
358 }
359 RouterOptScope scope(this);
360 return StartPop();
361 }
362
StartPop()363 bool PageRouterManager::StartPop()
364 {
365 CHECK_RUN_ON(JS);
366 auto currentPage = pageRouterStack_.empty() ? nullptr : pageRouterStack_.back().Upgrade();
367 CHECK_NULL_RETURN(currentPage, false);
368 auto pagePattern = currentPage->GetPattern<PagePattern>();
369 CHECK_NULL_RETURN(pagePattern, false);
370 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
371 CHECK_NULL_RETURN(pageInfo, false);
372 if (pageInfo->GetAlertCallback()) {
373 BackCheckAlert(RouterPageInfo());
374 return true;
375 }
376
377 if (pageRouterStack_.size() <= 1) {
378 if (!restorePageStack_.empty()) {
379 StartRestore(RouterPageInfo());
380 return true;
381 }
382 // the last page.
383 return false;
384 }
385
386 auto topNode = pageRouterStack_.back();
387 pageRouterStack_.pop_back();
388 if (!OnPopPage(true, true)) {
389 LOGE("fail to pop page");
390 pageRouterStack_.emplace_back(topNode);
391 return false;
392 }
393 currentPage = pageRouterStack_.empty() ? nullptr : pageRouterStack_.back().Upgrade();
394 CHECK_NULL_RETURN(currentPage, false);
395 pagePattern = currentPage->GetPattern<PagePattern>();
396 CHECK_NULL_RETURN(pagePattern, false);
397 pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
398 CHECK_NULL_RETURN(pageInfo, false);
399 pageInfo->ReplacePageParams("");
400 return true;
401 }
402
StartRestore(const RouterPageInfo & target)403 void PageRouterManager::StartRestore(const RouterPageInfo& target)
404 {
405 RouterPageInfo info = target;
406 auto tempStack = restorePageStack_;
407 if (target.url.empty()) {
408 info.url = tempStack.back();
409 tempStack.pop_back();
410 } else {
411 info.url = target.url;
412 while (!tempStack.empty() && tempStack.back() != info.url) {
413 tempStack.pop_back();
414 }
415 if (tempStack.empty()) {
416 LOGW("this url not find in current restore stack");
417 return;
418 }
419 tempStack.pop_back();
420 }
421
422 restorePageStack_ = tempStack;
423 StartClean();
424 PopPage("", false, false);
425 StartPush(info);
426 }
427
GetStackSize() const428 int32_t PageRouterManager::GetStackSize() const
429 {
430 CHECK_RUN_ON(JS);
431 return static_cast<int32_t>(pageRouterStack_.size());
432 }
433
GetState(int32_t & index,std::string & name,std::string & path)434 void PageRouterManager::GetState(int32_t& index, std::string& name, std::string& path)
435 {
436 CHECK_RUN_ON(JS);
437 if (pageRouterStack_.empty()) {
438 LOGE("fail to get page state due to stack is null");
439 return;
440 }
441 index = static_cast<int32_t>(pageRouterStack_.size());
442 auto pageNode = pageRouterStack_.back().Upgrade();
443 CHECK_NULL_VOID(pageNode);
444 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
445 CHECK_NULL_VOID(pagePattern);
446 auto pageInfo = pagePattern->GetPageInfo();
447 CHECK_NULL_VOID(pageInfo);
448 auto url = pageInfo->GetPageUrl();
449 auto pos = url.rfind(".js");
450 if (pos == url.length() - 3) {
451 url = url.substr(0, pos);
452 }
453 pos = url.rfind("/");
454 if (pos != std::string::npos) {
455 name = url.substr(pos + 1);
456 path = url.substr(0, pos + 1);
457 }
458 }
459
GetParams() const460 std::string PageRouterManager::GetParams() const
461 {
462 CHECK_RUN_ON(JS);
463 if (pageRouterStack_.empty()) {
464 LOGE("fail to get page param due to stack is null");
465 return "";
466 }
467 auto pageNode = pageRouterStack_.back().Upgrade();
468 CHECK_NULL_RETURN(pageNode, "");
469 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
470 CHECK_NULL_RETURN(pagePattern, "");
471 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
472 CHECK_NULL_RETURN(pageInfo, "");
473 return pageInfo->GetPageParams();
474 }
475
GetCurrentPageUrl()476 std::string PageRouterManager::GetCurrentPageUrl()
477 {
478 CHECK_RUN_ON(JS);
479 if (pageRouterStack_.empty()) {
480 LOGW("current page stack is empty");
481 return "";
482 }
483 auto pageNode = pageRouterStack_.back().Upgrade();
484 CHECK_NULL_RETURN(pageNode, "");
485 auto pagePattern = pageNode->GetPattern<PagePattern>();
486 CHECK_NULL_RETURN(pagePattern, "");
487 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
488 CHECK_NULL_RETURN(entryPageInfo, "");
489 return entryPageInfo->GetPagePath();
490 }
491
492 // Get the currently running JS page information in NG structure.
GetCurrentPageSourceMap(const RefPtr<AssetManager> & assetManager)493 RefPtr<Framework::RevSourceMap> PageRouterManager::GetCurrentPageSourceMap(const RefPtr<AssetManager>& assetManager)
494 {
495 CHECK_RUN_ON(JS);
496 if (pageRouterStack_.empty()) {
497 LOGW("current page stack is empty");
498 return nullptr;
499 }
500 auto pageNode = pageRouterStack_.back().Upgrade();
501 CHECK_NULL_RETURN(pageNode, nullptr);
502 auto pagePattern = pageNode->GetPattern<PagePattern>();
503 CHECK_NULL_RETURN(pagePattern, nullptr);
504 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
505 CHECK_NULL_RETURN(entryPageInfo, nullptr);
506 auto pageMap = entryPageInfo->GetPageMap();
507 if (pageMap) {
508 return pageMap;
509 }
510 // initialize page map.
511 std::string jsSourceMap;
512 // stage mode
513 auto container = Container::Current();
514 CHECK_NULL_RETURN(container, nullptr);
515 if (container->IsUseStageModel()) {
516 auto pagePath = entryPageInfo->GetPagePath();
517 auto moduleName = container->GetModuleName();
518 auto judgePath = moduleName + "/src/main/ets/" + pagePath.substr(0, pagePath.size() - 3) + ".ets";
519 if (Framework::GetAssetContentImpl(assetManager, "sourceMaps.map", jsSourceMap)) {
520 auto jsonPages = JsonUtil::ParseJsonString(jsSourceMap);
521 auto jsonPage = jsonPages->GetValue(judgePath)->ToString();
522 auto stagePageMap = MakeRefPtr<Framework::RevSourceMap>();
523 stagePageMap->Init(jsonPage);
524 entryPageInfo->SetPageMap(stagePageMap);
525 return stagePageMap;
526 }
527 } else {
528 if (Framework::GetAssetContentImpl(assetManager, entryPageInfo->GetPagePath() + ".map", jsSourceMap)) {
529 auto faPageMap = MakeRefPtr<Framework::RevSourceMap>();
530 faPageMap->Init(jsSourceMap);
531 entryPageInfo->SetPageMap(faPageMap);
532 return faPageMap;
533 }
534 }
535 LOGW("js source map load failed!");
536 return nullptr;
537 }
538
GetStackInfo()539 std::unique_ptr<JsonValue> PageRouterManager::GetStackInfo()
540 {
541 auto jsonRouterStack = JsonUtil::CreateArray(false);
542 auto restoreIter = restorePageStack_.begin();
543 while (restoreIter != restorePageStack_.end()) {
544 auto jsonItem = JsonUtil::Create(false);
545 jsonItem->Put("url", restoreIter->c_str());
546 jsonRouterStack->Put(jsonItem);
547 ++restoreIter;
548 }
549 auto iter = pageRouterStack_.begin();
550 while (iter != pageRouterStack_.end()) {
551 auto pageNode = iter->Upgrade();
552 CHECK_NULL_RETURN(pageNode, jsonRouterStack);
553 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
554 CHECK_NULL_RETURN(pagePattern, jsonRouterStack);
555 auto pageInfo = pagePattern->GetPageInfo();
556 CHECK_NULL_RETURN(pageInfo, jsonRouterStack);
557 auto url = pageInfo->GetPageUrl();
558 auto jsonItem = JsonUtil::Create(false);
559 jsonItem->Put("url", url.c_str());
560 jsonRouterStack->Put(jsonItem);
561 ++iter;
562 }
563 return jsonRouterStack;
564 }
565
RestoreRouterStack(std::unique_ptr<JsonValue> stackInfo)566 std::string PageRouterManager::RestoreRouterStack(std::unique_ptr<JsonValue> stackInfo)
567 {
568 if (!stackInfo->IsValid() || !stackInfo->IsArray()) {
569 LOGW("restore contentInfo is invalid");
570 return "";
571 }
572 int32_t stackSize = stackInfo->GetArraySize();
573 if (stackSize < 1) {
574 LOGW("restore stack size is invalid");
575 return "";
576 }
577
578 auto container = Container::Current();
579 CHECK_NULL_RETURN(container, "");
580 auto pipeline = container->GetPipelineContext();
581 CHECK_NULL_RETURN(pipeline, "");
582 auto context = DynamicCast<NG::PipelineContext>(pipeline);
583 auto stageManager = context ? context->GetStageManager() : nullptr;
584 CHECK_NULL_RETURN(stageManager, "");
585
586 for (int32_t index = 0; index < stackSize - 1; ++index) {
587 std::string url = stackInfo->GetArrayItem(index)->GetValue("url")->ToString();
588 // remove 2 useless character, as "XXX" to XXX
589 url = url.substr(1, url.size() - 2);
590 restorePageStack_.emplace_back(url);
591 }
592 std::string startUrl = stackInfo->GetArrayItem(stackSize - 1)->GetValue("url")->ToString();
593 // remove 2 useless character, as "XXX" to XXX
594 return startUrl.substr(1, startUrl.size() - 2);
595 }
596
GenerateNextPageId()597 int32_t PageRouterManager::GenerateNextPageId()
598 {
599 return ++pageId_;
600 }
601
FindPageInStack(const std::string & url,bool needIgnoreBegin)602 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStack(const std::string& url, bool needIgnoreBegin)
603 {
604 auto iter = std::find_if(needIgnoreBegin ? ++pageRouterStack_.rbegin() : pageRouterStack_.rbegin(),
605 pageRouterStack_.rend(), [url](const WeakPtr<FrameNode>& item) {
606 auto pageNode = item.Upgrade();
607 CHECK_NULL_RETURN(pageNode, false);
608 auto pagePattern = pageNode->GetPattern<PagePattern>();
609 CHECK_NULL_RETURN(pagePattern, false);
610 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
611 CHECK_NULL_RETURN(entryPageInfo, false);
612 return entryPageInfo->GetPageUrl() == url;
613 });
614 if (iter == pageRouterStack_.rend()) {
615 return { -1, nullptr };
616 }
617 // Returns to the forward position.
618 return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
619 }
620
PushOhmUrl(const RouterPageInfo & target)621 void PageRouterManager::PushOhmUrl(const RouterPageInfo& target)
622 {
623 RouterOptScope scope(this);
624 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
625 LOGE("router stack size is larger than max size 32.");
626 if (target.errorCallback != nullptr) {
627 target.errorCallback("The pages are pushed too much.", Framework::ERROR_CODE_PAGE_STACK_FULL);
628 }
629 return;
630 }
631 RouterPageInfo info = target;
632 info.path = info.url + ".js";
633 LOGD("router.Push pagePath = %{private}s", info.path.c_str());
634
635 if (target.routerMode == RouterMode::SINGLE) {
636 auto pageInfo = FindPageInStack(info.url);
637 if (pageInfo.second) {
638 // find page in stack, move postion and update params.
639 MovePageToFront(pageInfo.first, pageInfo.second, info, false);
640 return;
641 }
642 }
643
644 LoadPage(GenerateNextPageId(), info);
645 auto container = Container::Current();
646 CHECK_NULL_VOID(container);
647 auto pageUrlChecker = container->GetPageUrlChecker();
648 CHECK_NULL_VOID(pageUrlChecker);
649 auto taskExecutor = container->GetTaskExecutor();
650 CHECK_NULL_VOID(taskExecutor);
651 taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
652 TaskExecutor::TaskType::BACKGROUND);
653 }
654
StartPush(const RouterPageInfo & target)655 void PageRouterManager::StartPush(const RouterPageInfo& target)
656 {
657 CHECK_RUN_ON(JS);
658 RouterOptScope scope(this);
659 if (target.url.empty()) {
660 LOGE("router.Push uri is empty");
661 return;
662 }
663 #if !defined(PREVIEW)
664 if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
665 auto container = Container::Current();
666 CHECK_NULL_VOID(container);
667 auto pageUrlChecker = container->GetPageUrlChecker();
668 CHECK_NULL_VOID(pageUrlChecker);
669 auto instanceId = container->GetInstanceId();
670 auto taskExecutor = container->GetTaskExecutor();
671 CHECK_NULL_VOID(taskExecutor);
672 auto callback = [weak = AceType::WeakClaim(this), target, taskExecutor, instanceId]() {
673 ContainerScope scope(instanceId);
674 auto pageRouterManager = weak.Upgrade();
675 CHECK_NULL_VOID(pageRouterManager);
676 taskExecutor->PostTask(
677 [pageRouterManager, target]() { pageRouterManager->PushOhmUrl(target); }, TaskExecutor::TaskType::JS);
678 };
679
680 auto silentInstallErrorCallBack = [errorCallback = target.errorCallback, taskExecutor, instanceId](
681 int32_t errorCode, const std::string& errorMsg) {
682 ContainerScope scope(instanceId);
683 taskExecutor->PostTask([errorCallback, errorCode, errorMsg]() { errorCallback(errorMsg, errorCode); },
684 TaskExecutor::TaskType::JS);
685 };
686
687 pageUrlChecker->LoadPageUrl(target.url, callback, silentInstallErrorCallBack);
688 return;
689 }
690 #endif
691 if (!manifestParser_) {
692 LOGE("the router manifest parser is null.");
693 return;
694 }
695 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
696 LOGE("router stack size is larger than max size 32.");
697 if (target.errorCallback != nullptr) {
698 target.errorCallback("The pages are pushed too much.", Framework::ERROR_CODE_PAGE_STACK_FULL);
699 }
700 return;
701 }
702 RouterPageInfo info = target;
703 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
704 LOGD("router.Push pagePath = %{private}s", info.path.c_str());
705 if (info.path.empty()) {
706 LOGE("[Engine Log] this uri not support in route push.");
707 if (info.errorCallback != nullptr) {
708 info.errorCallback("The uri of router is not exist.", Framework::ERROR_CODE_URI_ERROR);
709 }
710 return;
711 }
712
713 CleanPageOverlay();
714
715 if (info.routerMode == RouterMode::SINGLE) {
716 auto pageInfo = FindPageInStack(info.url);
717 if (pageInfo.second) {
718 // find page in stack, move postion and update params.
719 MovePageToFront(pageInfo.first, pageInfo.second, info, false);
720 return;
721 }
722 }
723
724 LoadPage(GenerateNextPageId(), info);
725 }
726
ReplaceOhmUrl(const RouterPageInfo & target)727 void PageRouterManager::ReplaceOhmUrl(const RouterPageInfo& target)
728 {
729 RouterOptScope scope(this);
730 RouterPageInfo info = target;
731 info.path = info.url + ".js";
732 LOGD("router.Push pagePath = %{private}s", info.path.c_str());
733
734 PopPage("", false, false);
735
736 if (info.routerMode == RouterMode::SINGLE) {
737 auto pageInfo = FindPageInStack(info.url);
738 if (pageInfo.second) {
739 // find page in stack, move postion and update params.
740 MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
741 return;
742 }
743 }
744
745 LoadPage(GenerateNextPageId(), info, false, false);
746 auto container = Container::Current();
747 CHECK_NULL_VOID(container);
748 auto pageUrlChecker = container->GetPageUrlChecker();
749 CHECK_NULL_VOID(pageUrlChecker);
750 auto taskExecutor = container->GetTaskExecutor();
751 CHECK_NULL_VOID(taskExecutor);
752 taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
753 TaskExecutor::TaskType::BACKGROUND);
754 }
755
StartReplace(const RouterPageInfo & target)756 void PageRouterManager::StartReplace(const RouterPageInfo& target)
757 {
758 CHECK_RUN_ON(JS);
759 CleanPageOverlay();
760 RouterOptScope scope(this);
761 if (target.url.empty()) {
762 LOGE("router.Push uri is empty");
763 return;
764 }
765 #if !defined(PREVIEW)
766 if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
767 auto container = Container::Current();
768 CHECK_NULL_VOID(container);
769 auto pageUrlChecker = container->GetPageUrlChecker();
770 CHECK_NULL_VOID(pageUrlChecker);
771 auto instanceId = container->GetInstanceId();
772 auto taskExecutor = container->GetTaskExecutor();
773 CHECK_NULL_VOID(taskExecutor);
774 auto callback = [weak = AceType::WeakClaim(this), target, taskExecutor, instanceId]() {
775 ContainerScope scope(instanceId);
776 auto pageRouterManager = weak.Upgrade();
777 CHECK_NULL_VOID(pageRouterManager);
778 taskExecutor->PostTask([pageRouterManager, target]() { pageRouterManager->ReplaceOhmUrl(target); },
779 TaskExecutor::TaskType::JS);
780 };
781
782 auto silentInstallErrorCallBack = [errorCallback = target.errorCallback, taskExecutor, instanceId](
783 int32_t errorCode, const std::string& errorMsg) {
784 ContainerScope scope(instanceId);
785 taskExecutor->PostTask([errorCallback, errorCode, errorMsg]() { errorCallback(errorMsg, errorCode); },
786 TaskExecutor::TaskType::JS);
787 };
788
789 pageUrlChecker->LoadPageUrl(target.url, callback, silentInstallErrorCallBack);
790 return;
791 }
792 #endif
793 if (!manifestParser_) {
794 LOGE("the router manifest parser is null.");
795 return;
796 }
797 RouterPageInfo info = target;
798 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
799 LOGD("router.Push pagePath = %{private}s", info.path.c_str());
800 if (info.path.empty()) {
801 LOGE("[Engine Log] this uri not support in route push.");
802 if (info.errorCallback != nullptr) {
803 info.errorCallback("The uri of router is not exist.", Framework::ERROR_CODE_URI_ERROR_LITE);
804 }
805 return;
806 }
807
808 PopPage("", false, false);
809
810 if (info.routerMode == RouterMode::SINGLE) {
811 auto pageInfo = FindPageInStack(info.url);
812 if (pageInfo.second) {
813 // find page in stack, move position and update params.
814 MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
815 return;
816 }
817 }
818
819 LoadPage(GenerateNextPageId(), info, false, false);
820 }
821
StartBack(const RouterPageInfo & target)822 void PageRouterManager::StartBack(const RouterPageInfo& target)
823 {
824 CleanPageOverlay();
825 if (target.url.empty()) {
826 size_t pageRouteSize = pageRouterStack_.size();
827 if (pageRouteSize <= 1) {
828 if (!restorePageStack_.empty()) {
829 StartRestore(RouterPageInfo());
830 return;
831 }
832 LOGI("router stack is only one, back to desktop");
833 ExitToDesktop();
834 return;
835 }
836 PopPage(target.params, true, true);
837 return;
838 }
839
840 auto pageInfo = FindPageInStack(target.url, true);
841 if (pageInfo.second) {
842 // find page in stack, pop to specified index.
843 RouterPageInfo info = target;
844 #if !defined(PREVIEW)
845 if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
846 info.path = info.url + ".js";
847 LOGD("router.Push pagePath = %{private}s", info.path.c_str());
848 PopPageToIndex(pageInfo.first, info.params, true, true);
849 return;
850 }
851 #endif
852 if (!manifestParser_) {
853 LOGE("the router manifest parser is null.");
854 return;
855 }
856
857 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
858 LOGD("router.Push pagePath = %{private}s", info.path.c_str());
859 if (info.path.empty()) {
860 LOGE("[Engine Log] this uri not support in route push.");
861 return;
862 }
863 PopPageToIndex(pageInfo.first, info.params, true, true);
864 return;
865 }
866 LOGW("fail to find specified page to pop");
867 if (!restorePageStack_.empty()) {
868 StartRestore(target);
869 }
870 }
871
BackCheckAlert(const RouterPageInfo & target)872 void PageRouterManager::BackCheckAlert(const RouterPageInfo& target)
873 {
874 RouterOptScope scope(this);
875 if (pageRouterStack_.empty()) {
876 LOGI("page route stack is empty");
877 return;
878 }
879 auto currentPage = pageRouterStack_.back().Upgrade();
880 CHECK_NULL_VOID(currentPage);
881 auto pagePattern = currentPage->GetPattern<PagePattern>();
882 CHECK_NULL_VOID(pagePattern);
883 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
884 CHECK_NULL_VOID(pageInfo);
885 if (pageInfo->GetAlertCallback()) {
886 ngBackTarget_ = target;
887 auto pipelineContext = PipelineContext::GetCurrentContext();
888 auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
889 CHECK_NULL_VOID(overlayManager);
890 overlayManager->ShowDialog(
891 pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
892 return;
893 }
894 StartBack(target);
895 }
896
LoadPage(int32_t pageId,const RouterPageInfo & target,bool needHideLast,bool needTransition)897 void PageRouterManager::LoadPage(int32_t pageId, const RouterPageInfo& target, bool needHideLast, bool needTransition)
898 {
899 ACE_SCOPED_TRACE("PageRouterManager::LoadPage");
900 CHECK_RUN_ON(JS);
901 LOGI("PageRouterManager LoadPage[%{public}d]: %{public}s.", pageId, target.url.c_str());
902 auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, target.params);
903 auto pagePattern = AceType::MakeRefPtr<PagePattern>(entryPageInfo);
904 std::unordered_map<std::string, std::string> reportData { { "pageUrl", target.url } };
905 ResSchedReportScope reportScope("push_page", reportData);
906 auto pageNode =
907 FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
908 pageNode->SetHostPageId(pageId);
909 pageRouterStack_.emplace_back(pageNode);
910 auto result = loadJs_(target.path, target.errorCallback);
911 if (pageNode->GetChildren().empty()) {
912 // try to load named route
913 result = loadNamedRouter_(target.url, target.isNamedRouterMode);
914 if (!result && target.isNamedRouterMode && target.errorCallback) {
915 target.errorCallback("The named route is not exist.", Framework::ERROR_CODE_NAMED_ROUTE_ERROR);
916 }
917 }
918 if (target.errorCallback != nullptr) {
919 target.errorCallback("", Framework::ERROR_CODE_NO_ERROR);
920 }
921 if (!result) {
922 LOGE("fail to load page file");
923 pageRouterStack_.pop_back();
924 return;
925 }
926 if (!OnPageReady(pageNode, needHideLast, needTransition)) {
927 LOGE("fail to mount page");
928 pageRouterStack_.pop_back();
929 return;
930 }
931 AccessibilityEventType type = AccessibilityEventType::CHANGE;
932 pageNode->OnAccessibilityEvent(type);
933 LOGI("PageRouterManager LoadPage[%{public}d]: %{public}s. success", pageId, target.url.c_str());
934 }
935
LoadCard(int32_t pageId,const RouterPageInfo & target,const std::string & params,int64_t cardId,bool,bool needHideLast)936 void PageRouterManager::LoadCard(int32_t pageId, const RouterPageInfo& target, const std::string& params,
937 int64_t cardId, bool /*isRestore*/, bool needHideLast)
938 {
939 CHECK_RUN_ON(JS);
940 auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, params);
941 auto pagePattern = AceType::MakeRefPtr<PagePattern>(entryPageInfo);
942 auto pageNode =
943 FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
944 pageNode->SetHostPageId(pageId);
945 pageRouterStack_.emplace_back(pageNode);
946
947 if (!loadCard_) {
948 LOGE("PageRouterManager loadCard_ is nullptr");
949 return;
950 }
951 auto result = loadCard_(target.url, cardId);
952 if (!result) {
953 LOGE("fail to load page file");
954 pageRouterStack_.pop_back();
955 return;
956 }
957
958 if (!OnPageReady(pageNode, needHideLast, false, isCardRouter_, cardId)) {
959 LOGE("fail to mount page");
960 pageRouterStack_.pop_back();
961 return;
962 }
963 }
964
MovePageToFront(int32_t index,const RefPtr<FrameNode> & pageNode,const RouterPageInfo & target,bool needHideLast,bool forceShowCurrent,bool needTransition)965 void PageRouterManager::MovePageToFront(int32_t index, const RefPtr<FrameNode>& pageNode, const RouterPageInfo& target,
966 bool needHideLast, bool forceShowCurrent, bool needTransition)
967 {
968 LOGD("MovePageToFront to index: %{public}d", index);
969 if (target.errorCallback != nullptr) {
970 target.errorCallback("", Framework::ERROR_CODE_NO_ERROR);
971 }
972
973 // update param first.
974 CHECK_NULL_VOID(pageNode);
975 auto pagePattern = pageNode->GetPattern<PagePattern>();
976 CHECK_NULL_VOID(pagePattern);
977 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
978 CHECK_NULL_VOID(pageInfo);
979
980 if (index == static_cast<int32_t>(pageRouterStack_.size() - 1)) {
981 LOGD("already on the top");
982 pageInfo->ReplacePageParams(target.params);
983 if (forceShowCurrent) {
984 pageNode->GetRenderContext()->ResetPageTransitionEffect();
985 StageManager::FirePageShow(pageNode, PageTransitionType::NONE);
986 }
987 return;
988 }
989 CHECK_NULL_VOID(pageNode);
990 auto container = Container::Current();
991 CHECK_NULL_VOID(container);
992 auto pipeline = container->GetPipelineContext();
993 CHECK_NULL_VOID(pipeline);
994 auto context = DynamicCast<NG::PipelineContext>(pipeline);
995 auto stageManager = context ? context->GetStageManager() : nullptr;
996 CHECK_NULL_VOID(stageManager);
997
998 // clean pageNode on index position.
999 auto iter = pageRouterStack_.begin();
1000 std::advance(iter, index);
1001 auto last = pageRouterStack_.erase(iter);
1002 // push pageNode to top.
1003 pageRouterStack_.emplace_back(pageNode);
1004 std::string tempParam;
1005 tempParam = pageInfo->ReplacePageParams(target.params);
1006 if (!stageManager->MovePageToFront(pageNode, needHideLast, needTransition)) {
1007 LOGE("fail to move page to front");
1008 // restore position and param.
1009 pageRouterStack_.pop_back();
1010 pageRouterStack_.insert(last, pageNode);
1011 if (!tempParam.empty()) {
1012 pageInfo->ReplacePageParams(tempParam);
1013 }
1014 }
1015 }
1016
FlushFrontend()1017 void PageRouterManager::FlushFrontend()
1018 {
1019 auto currentPage = pageRouterStack_.back().Upgrade();
1020 CHECK_NULL_VOID(currentPage);
1021 auto customNode = DynamicCast<CustomNode>(currentPage->GetFirstChild());
1022 CHECK_NULL_VOID(customNode);
1023 customNode->FlushReload();
1024 }
1025
PopPage(const std::string & params,bool needShowNext,bool needTransition)1026 void PageRouterManager::PopPage(const std::string& params, bool needShowNext, bool needTransition)
1027 {
1028 CHECK_RUN_ON(JS);
1029 if (pageRouterStack_.empty()) {
1030 LOGE("page router stack size is illegal");
1031 return;
1032 }
1033 if (needShowNext && (pageRouterStack_.size() == 1)) {
1034 LOGE("page router stack size is only one, can not show next");
1035 return;
1036 }
1037 auto topNode = pageRouterStack_.back();
1038 pageRouterStack_.pop_back();
1039 if (!needShowNext) {
1040 if (!OnPopPage(needShowNext, needTransition)) {
1041 LOGE("fail to pop page");
1042 pageRouterStack_.emplace_back(topNode);
1043 }
1044 return;
1045 }
1046
1047 // update param first.
1048 auto nextNode = pageRouterStack_.back().Upgrade();
1049 CHECK_NULL_VOID(nextNode);
1050 auto pagePattern = nextNode->GetPattern<PagePattern>();
1051 CHECK_NULL_VOID(pagePattern);
1052 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1053 CHECK_NULL_VOID(pageInfo);
1054 auto temp = pageInfo->ReplacePageParams(params);
1055
1056 if (OnPopPage(needShowNext, needTransition)) {
1057 return;
1058 }
1059 LOGE("fail to pop page");
1060 // restore stack and pageParam.
1061 pageRouterStack_.emplace_back(topNode);
1062 pageInfo->ReplacePageParams(temp);
1063 }
1064
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)1065 void PageRouterManager::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
1066 {
1067 LOGD("PopPageToIndex to index: %{public}d", index);
1068 std::list<WeakPtr<FrameNode>> temp;
1069 std::swap(temp, pageRouterStack_);
1070 auto iter = temp.begin();
1071 for (int32_t current = 0; current <= index; ++current) {
1072 pageRouterStack_.emplace_back(*iter);
1073 ++iter;
1074 }
1075
1076 // update param first.
1077 auto nextNode = pageRouterStack_.back().Upgrade();
1078 CHECK_NULL_VOID(nextNode);
1079 auto pagePattern = nextNode->GetPattern<PagePattern>();
1080 CHECK_NULL_VOID(pagePattern);
1081 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1082 CHECK_NULL_VOID(pageInfo);
1083 auto tempParam = pageInfo->ReplacePageParams(params);
1084
1085 if (OnPopPageToIndex(index, needShowNext, needTransition)) {
1086 return;
1087 }
1088 LOGE("fail to pop page to index");
1089 // restore stack and pageParam.
1090 std::swap(temp, pageRouterStack_);
1091 pageInfo->ReplacePageParams(tempParam);
1092 }
1093
OnPageReady(const RefPtr<FrameNode> & pageNode,bool needHideLast,bool needTransition,bool isCardRouter,int64_t cardId)1094 bool PageRouterManager::OnPageReady(
1095 const RefPtr<FrameNode>& pageNode, bool needHideLast, bool needTransition, bool isCardRouter, int64_t cardId)
1096 {
1097 auto container = Container::Current();
1098 CHECK_NULL_RETURN(container, false);
1099 RefPtr<PipelineBase> pipeline;
1100 if (isCardRouter) {
1101 auto weak = container->GetCardPipeline(cardId);
1102 pipeline = weak.Upgrade();
1103 CHECK_NULL_RETURN(pipeline, false);
1104 } else {
1105 pipeline = container->GetPipelineContext();
1106 CHECK_NULL_RETURN(pipeline, false);
1107 }
1108
1109 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1110 auto stageManager = context ? context->GetStageManager() : nullptr;
1111 if (stageManager) {
1112 return stageManager->PushPage(pageNode, needHideLast, needTransition);
1113 }
1114 LOGE("fail to push page due to stage manager is nullptr");
1115 return false;
1116 }
1117
OnPopPage(bool needShowNext,bool needTransition)1118 bool PageRouterManager::OnPopPage(bool needShowNext, bool needTransition)
1119 {
1120 auto container = Container::Current();
1121 CHECK_NULL_RETURN(container, false);
1122 auto pipeline = container->GetPipelineContext();
1123 CHECK_NULL_RETURN(pipeline, false);
1124 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1125 auto stageManager = context ? context->GetStageManager() : nullptr;
1126 if (stageManager) {
1127 return stageManager->PopPage(needShowNext, needTransition);
1128 }
1129 LOGE("fail to pop page due to stage manager is nullptr");
1130 return false;
1131 }
1132
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)1133 bool PageRouterManager::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
1134 {
1135 auto container = Container::Current();
1136 CHECK_NULL_RETURN(container, false);
1137 auto pipeline = container->GetPipelineContext();
1138 CHECK_NULL_RETURN(pipeline, false);
1139 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1140 auto stageManager = context ? context->GetStageManager() : nullptr;
1141 if (stageManager) {
1142 return stageManager->PopPageToIndex(index, needShowNext, needTransition);
1143 }
1144 LOGE("fail to pop page to index due to stage manager is nullptr");
1145 return false;
1146 }
1147
OnCleanPageStack()1148 bool PageRouterManager::OnCleanPageStack()
1149 {
1150 auto container = Container::Current();
1151 CHECK_NULL_RETURN(container, false);
1152 auto pipeline = container->GetPipelineContext();
1153 CHECK_NULL_RETURN(pipeline, false);
1154 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1155 auto stageManager = context ? context->GetStageManager() : nullptr;
1156 if (stageManager) {
1157 return stageManager->CleanPageStack();
1158 }
1159 LOGE("fail to pop page to index due to stage manager is nullptr");
1160 return false;
1161 }
1162
CleanPageOverlay()1163 void PageRouterManager::CleanPageOverlay()
1164 {
1165 auto container = Container::Current();
1166 CHECK_NULL_VOID(container);
1167 auto pipeline = container->GetPipelineContext();
1168 CHECK_NULL_VOID(pipeline);
1169 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1170 CHECK_NULL_VOID(context);
1171 auto overlayManager = context->GetOverlayManager();
1172 CHECK_NULL_VOID(overlayManager);
1173 auto taskExecutor = context->GetTaskExecutor();
1174 CHECK_NULL_VOID_NOLOG(taskExecutor);
1175 auto sharedManager = context->GetSharedOverlayManager();
1176 if (sharedManager) {
1177 sharedManager->StopSharedTransition();
1178 }
1179
1180 if (overlayManager->RemoveOverlay(true, true)) {
1181 LOGI("clean page overlay.");
1182 }
1183 }
1184 } // namespace OHOS::Ace::NG
1185