• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 constexpr int32_t SUB_STR_LENGTH = 7;
46 
ExitToDesktop()47 void ExitToDesktop()
48 {
49     auto container = Container::Current();
50     CHECK_NULL_VOID(container);
51     auto taskExecutor = container->GetTaskExecutor();
52     CHECK_NULL_VOID(taskExecutor);
53     taskExecutor->PostTask(
54         [] {
55             auto pipeline = PipelineContext::GetCurrentContext();
56             CHECK_NULL_VOID(pipeline);
57             pipeline->Finish(false);
58         },
59         TaskExecutor::TaskType::UI);
60 }
61 
62 } // namespace
63 
RunPage(const std::string & url,const std::string & params)64 void PageRouterManager::RunPage(const std::string& url, const std::string& params)
65 {
66     CHECK_RUN_ON(JS);
67     RouterPageInfo info { url };
68     if (!info.url.empty()) {
69         info.path = manifestParser_->GetRouter()->GetPagePath(url);
70     } else {
71         info.path = manifestParser_->GetRouter()->GetEntry();
72         info.url = manifestParser_->GetRouter()->GetEntry("");
73     }
74     LOGD("router.Push pagePath = %{private}s", info.url.c_str());
75     RouterOptScope scope(this);
76     LoadPage(GenerateNextPageId(), info, params);
77 }
78 
RunCard(const std::string & url,const std::string & params,int64_t cardId)79 void PageRouterManager::RunCard(const std::string& url, const std::string& params, int64_t cardId)
80 {
81     CHECK_RUN_ON(JS);
82     RouterPageInfo info { url };
83 #ifndef PREVIEW
84     if (!info.url.empty()) {
85         info.path = manifestParser_->GetRouter()->GetPagePath(url);
86     } else {
87         info.path = manifestParser_->GetRouter()->GetEntry();
88         info.url = manifestParser_->GetRouter()->GetEntry("");
89     }
90 #endif
91     LoadCard(0, info, params, cardId);
92 }
93 
Push(const RouterPageInfo & target,const std::string & params,RouterMode mode)94 void PageRouterManager::Push(const RouterPageInfo& target, const std::string& params, RouterMode mode)
95 {
96     CHECK_RUN_ON(JS);
97     if (inRouterOpt_) {
98         LOGI("in router opt, post push router task");
99         auto context = PipelineContext::GetCurrentContext();
100         CHECK_NULL_VOID(context);
101         context->PostAsyncEvent([weak = WeakClaim(this), target, params, mode]() {
102             auto router = weak.Upgrade();
103             CHECK_NULL_VOID(router);
104             router->Push(target, params, mode);
105         });
106         return;
107     }
108     StartPush(target, params, mode);
109 }
110 
PushWithCallback(const RouterPageInfo & target,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback,RouterMode mode)111 void PageRouterManager::PushWithCallback(const RouterPageInfo& target, const std::string& params,
112     const std::function<void(const std::string&, int32_t)>& errorCallback, RouterMode mode)
113 {
114     CHECK_RUN_ON(JS);
115     if (inRouterOpt_) {
116         LOGI("in router opt, post push router task");
117         auto context = PipelineContext::GetCurrentContext();
118         CHECK_NULL_VOID(context);
119         context->PostAsyncEvent([weak = WeakClaim(this), target, params, mode, errorCallback]() {
120             auto router = weak.Upgrade();
121             CHECK_NULL_VOID(router);
122             router->PushWithCallback(target, params, errorCallback, mode);
123         });
124         return;
125     }
126     StartPush(target, params, mode, errorCallback);
127 }
128 
Replace(const RouterPageInfo & target,const std::string & params,RouterMode mode)129 void PageRouterManager::Replace(const RouterPageInfo& target, const std::string& params, RouterMode mode)
130 {
131     CHECK_RUN_ON(JS);
132     if (inRouterOpt_) {
133         LOGI("in router opt, post replace router task");
134         auto context = PipelineContext::GetCurrentContext();
135         CHECK_NULL_VOID(context);
136         context->PostAsyncEvent([weak = WeakClaim(this), target, params, mode]() {
137             auto router = weak.Upgrade();
138             CHECK_NULL_VOID(router);
139             router->Replace(target, params, mode);
140         });
141         return;
142     }
143     StartReplace(target, params, mode);
144 }
145 
ReplaceWithCallback(const RouterPageInfo & target,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback,RouterMode mode)146 void PageRouterManager::ReplaceWithCallback(const RouterPageInfo& target, const std::string& params,
147     const std::function<void(const std::string&, int32_t)>& errorCallback, RouterMode mode)
148 {
149     CHECK_RUN_ON(JS);
150     if (inRouterOpt_) {
151         LOGI("in router opt, post replace router task");
152         auto context = PipelineContext::GetCurrentContext();
153         CHECK_NULL_VOID(context);
154         context->PostAsyncEvent([weak = WeakClaim(this), target, params, mode, errorCallback]() {
155             auto router = weak.Upgrade();
156             CHECK_NULL_VOID(router);
157             router->ReplaceWithCallback(target, params, errorCallback, mode);
158         });
159         return;
160     }
161     StartReplace(target, params, mode, errorCallback);
162 }
163 
BackWithTarget(const RouterPageInfo & target,const std::string & params)164 void PageRouterManager::BackWithTarget(const RouterPageInfo& target, const std::string& params)
165 {
166     CHECK_RUN_ON(JS);
167     LOGD("router.Back path = %{private}s", target.url.c_str());
168     if (inRouterOpt_) {
169         LOGI("in router opt, post back router task");
170         auto context = PipelineContext::GetCurrentContext();
171         CHECK_NULL_VOID(context);
172         context->PostAsyncEvent([weak = WeakClaim(this), target, params]() {
173             auto router = weak.Upgrade();
174             CHECK_NULL_VOID(router);
175             router->BackWithTarget(target, params);
176         });
177         return;
178     }
179     BackCheckAlert(target, params);
180 }
181 
Clear()182 void PageRouterManager::Clear()
183 {
184     CHECK_RUN_ON(JS);
185     if (inRouterOpt_) {
186         LOGI("in router opt, post clear router task");
187         auto context = PipelineContext::GetCurrentContext();
188         CHECK_NULL_VOID(context);
189         context->PostAsyncEvent([weak = WeakClaim(this)]() {
190             auto router = weak.Upgrade();
191             CHECK_NULL_VOID(router);
192             router->Clear();
193         });
194         return;
195     }
196     StartClean();
197 }
198 
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)199 void PageRouterManager::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)>&& callback)
200 {
201     auto currentPage = pageRouterStack_.back().Upgrade();
202     CHECK_NULL_VOID(currentPage);
203     auto pagePattern = currentPage->GetPattern<PagePattern>();
204     CHECK_NULL_VOID(pagePattern);
205     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
206     CHECK_NULL_VOID(pageInfo);
207     ClearAlertCallback(pageInfo);
208 
209     DialogProperties dialogProperties = {
210         .content = message,
211         .autoCancel = false,
212         .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
213             { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
214         .onSuccess =
215             [weak = AceType::WeakClaim(this), callback](int32_t successType, int32_t successIndex) {
216                 LOGI("showDialog successType: %{public}d, successIndex: %{public}d", successType, successIndex);
217                 if (!successType) {
218                     callback(successIndex);
219                     if (successIndex) {
220                         auto router = weak.Upgrade();
221                         CHECK_NULL_VOID(router);
222                         router->StartBack(router->ngBackUri_, router->backParam_, true);
223                     }
224                 }
225             },
226     };
227 
228     pageInfo->SetDialogProperties(dialogProperties);
229     pageInfo->SetAlertCallback(std::move(callback));
230 }
231 
DisableAlertBeforeBackPage()232 void PageRouterManager::DisableAlertBeforeBackPage()
233 {
234     auto currentPage = pageRouterStack_.back().Upgrade();
235     CHECK_NULL_VOID(currentPage);
236     auto pagePattern = currentPage->GetPattern<PagePattern>();
237     CHECK_NULL_VOID(pagePattern);
238     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
239     CHECK_NULL_VOID(pageInfo);
240     ClearAlertCallback(pageInfo);
241     pageInfo->SetAlertCallback(nullptr);
242 }
243 
ClearAlertCallback(const RefPtr<PageInfo> & pageInfo)244 void PageRouterManager::ClearAlertCallback(const RefPtr<PageInfo>& pageInfo)
245 {
246     if (pageInfo->GetAlertCallback()) {
247         // notify to clear js reference
248         auto alertCallback = pageInfo->GetAlertCallback();
249         alertCallback(static_cast<int32_t>(Framework::AlertState::RECOVERY));
250         pageInfo->SetAlertCallback(nullptr);
251     }
252 }
253 
StartClean()254 void PageRouterManager::StartClean()
255 {
256     RouterOptScope scope(this);
257     if (pageRouterStack_.size() <= 1) {
258         LOGW("current page stack can not clean, %{public}d", static_cast<int32_t>(pageRouterStack_.size()));
259         return;
260     }
261     std::list<WeakPtr<FrameNode>> temp;
262     std::swap(temp, pageRouterStack_);
263     pageRouterStack_.emplace_back(temp.back());
264     if (!OnCleanPageStack()) {
265         LOGE("fail to clean page");
266         std::swap(temp, pageRouterStack_);
267     }
268 }
269 
Pop()270 bool PageRouterManager::Pop()
271 {
272     CHECK_RUN_ON(JS);
273     if (inRouterOpt_) {
274         LOGE("in router opt, post Pop router task failed");
275         return false;
276     }
277     return StartPop();
278 }
279 
StartPop()280 bool PageRouterManager::StartPop()
281 {
282     CHECK_RUN_ON(JS);
283     RouterOptScope scope(this);
284     if (pageRouterStack_.size() <= 1) {
285         // the last page.
286         return false;
287     }
288 
289     auto currentPage = pageRouterStack_.back().Upgrade();
290     CHECK_NULL_RETURN(currentPage, false);
291     auto pagePattern = currentPage->GetPattern<PagePattern>();
292     CHECK_NULL_RETURN(pagePattern, false);
293     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
294     CHECK_NULL_RETURN(pageInfo, false);
295     if (pageInfo->GetAlertCallback()) {
296         BackCheckAlert(NG::RouterPageInfo(), "");
297         return true;
298     }
299 
300     auto topNode = pageRouterStack_.back();
301     pageRouterStack_.pop_back();
302     if (!OnPopPage(true, true)) {
303         LOGE("fail to pop page");
304         pageRouterStack_.emplace_back(topNode);
305         return false;
306     }
307     return true;
308 }
309 
GetStackSize() const310 int32_t PageRouterManager::GetStackSize() const
311 {
312     CHECK_RUN_ON(JS);
313     return static_cast<int32_t>(pageRouterStack_.size());
314 }
315 
GetState(int32_t & index,std::string & name,std::string & path)316 void PageRouterManager::GetState(int32_t& index, std::string& name, std::string& path)
317 {
318     CHECK_RUN_ON(JS);
319     if (pageRouterStack_.empty()) {
320         LOGE("fail to get page state due to stack is null");
321         return;
322     }
323     index = static_cast<int32_t>(pageRouterStack_.size());
324     auto pageNode = pageRouterStack_.back().Upgrade();
325     CHECK_NULL_VOID(pageNode);
326     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
327     CHECK_NULL_VOID(pagePattern);
328     auto pageInfo = pagePattern->GetPageInfo();
329     CHECK_NULL_VOID(pageInfo);
330     auto url = pageInfo->GetPageUrl();
331     auto pos = url.rfind(".js");
332     if (pos == url.length() - 3) {
333         url = url.substr(0, pos);
334     }
335     pos = url.rfind("/");
336     if (pos != std::string::npos) {
337         name = url.substr(pos + 1);
338         path = url.substr(0, pos + 1);
339     }
340 }
341 
GetParams() const342 std::string PageRouterManager::GetParams() const
343 {
344     CHECK_RUN_ON(JS);
345     if (pageRouterStack_.empty()) {
346         LOGE("fail to get page param due to stack is null");
347         return "";
348     }
349     auto pageNode = pageRouterStack_.back().Upgrade();
350     CHECK_NULL_RETURN(pageNode, "");
351     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
352     CHECK_NULL_RETURN(pagePattern, "");
353     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
354     CHECK_NULL_RETURN(pageInfo, "");
355     return pageInfo->GetPageParams();
356 }
357 
GetCurrentPageUrl()358 std::string PageRouterManager::GetCurrentPageUrl()
359 {
360     CHECK_RUN_ON(JS);
361     if (pageRouterStack_.empty()) {
362         LOGW("current page stack is empty");
363         return "";
364     }
365     auto pageNode = pageRouterStack_.back().Upgrade();
366     CHECK_NULL_RETURN(pageNode, "");
367     auto pagePattern = pageNode->GetPattern<PagePattern>();
368     CHECK_NULL_RETURN(pagePattern, "");
369     auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
370     CHECK_NULL_RETURN(entryPageInfo, "");
371     return entryPageInfo->GetPagePath();
372 }
373 
374 // Get the currently running JS page information in NG structure.
GetCurrentPageSourceMap(const RefPtr<AssetManager> & assetManager)375 RefPtr<Framework::RevSourceMap> PageRouterManager::GetCurrentPageSourceMap(const RefPtr<AssetManager>& assetManager)
376 {
377     CHECK_RUN_ON(JS);
378     if (pageRouterStack_.empty()) {
379         LOGW("current page stack is empty");
380         return nullptr;
381     }
382     auto pageNode = pageRouterStack_.back().Upgrade();
383     CHECK_NULL_RETURN(pageNode, nullptr);
384     auto pagePattern = pageNode->GetPattern<PagePattern>();
385     CHECK_NULL_RETURN(pagePattern, nullptr);
386     auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
387     CHECK_NULL_RETURN(entryPageInfo, nullptr);
388     auto pageMap = entryPageInfo->GetPageMap();
389     if (pageMap) {
390         return pageMap;
391     }
392     // initialize page map.
393     std::string jsSourceMap;
394     if (Framework::GetAssetContentImpl(assetManager, entryPageInfo->GetPagePath() + ".map", jsSourceMap)) {
395         auto pageMap = MakeRefPtr<Framework::RevSourceMap>();
396         pageMap->Init(jsSourceMap);
397         entryPageInfo->SetPageMap(pageMap);
398         return pageMap;
399     }
400     LOGW("js source map load failed!");
401     return nullptr;
402 }
403 
GenerateNextPageId()404 int32_t PageRouterManager::GenerateNextPageId()
405 {
406     return ++pageId_;
407 }
408 
FindPageInStack(const std::string & url)409 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStack(const std::string& url)
410 {
411     auto iter = std::find_if(pageRouterStack_.rbegin(), pageRouterStack_.rend(), [url](const WeakPtr<FrameNode>& item) {
412         auto pageNode = item.Upgrade();
413         CHECK_NULL_RETURN(pageNode, false);
414         auto pagePattern = pageNode->GetPattern<PagePattern>();
415         CHECK_NULL_RETURN(pagePattern, false);
416         auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
417         CHECK_NULL_RETURN(entryPageInfo, false);
418         return entryPageInfo->GetPageUrl() == url;
419     });
420     if (iter == pageRouterStack_.rend()) {
421         return { -1, nullptr };
422     }
423     // Returns to the forward position.
424     return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
425 }
426 
PushOhmUrl(const RouterPageInfo & target,const std::string & params,RouterMode mode,const std::function<void (const std::string &,int32_t)> & errorCallback)427 void PageRouterManager::PushOhmUrl(const RouterPageInfo& target, const std::string& params, RouterMode mode,
428     const std::function<void(const std::string&, int32_t)>& errorCallback)
429 {
430     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
431         LOGE("router stack size is larger than max size 32.");
432         return;
433     }
434     std::string url = target.url;
435     std::string pagePath = url + ".js";
436     LOGD("router.Push pagePath = %{private}s", pagePath.c_str());
437 
438     if (mode == RouterMode::SINGLE) {
439         auto pageInfo = FindPageInStack(url);
440         if (pageInfo.second) {
441             // find page in stack, move postion and update params.
442             MovePageToFront(pageInfo.first, pageInfo.second, params, false);
443             return;
444         }
445     }
446 
447     RouterPageInfo info { url };
448     info.path = pagePath;
449     LoadPage(GenerateNextPageId(), info, params, false, true, true, errorCallback);
450 }
451 
StartPush(const RouterPageInfo & target,const std::string & params,RouterMode mode,const std::function<void (const std::string &,int32_t)> & errorCallback)452 void PageRouterManager::StartPush(const RouterPageInfo& target, const std::string& params, RouterMode mode,
453     const std::function<void(const std::string&, int32_t)>& errorCallback)
454 {
455     CHECK_RUN_ON(JS);
456     RouterOptScope scope(this);
457     if (target.url.empty()) {
458         LOGE("router.Push uri is empty");
459         return;
460     }
461     if (target.url.substr(0, SUB_STR_LENGTH) == "@bundle") {
462         auto container = Container::Current();
463         CHECK_NULL_VOID(container);
464         auto pageUrlChecker = container->GetPageUrlChecker();
465         CHECK_NULL_VOID(pageUrlChecker);
466         auto instanceId = container->GetInstanceId();
467         auto taskExecutor = container->GetTaskExecutor();
468         CHECK_NULL_VOID(taskExecutor);
469         auto callback =
470             [weak = AceType::WeakClaim(this), target, params, mode, errorCallback, taskExecutor, instanceId]() {
471                 ContainerScope scope(instanceId);
472                 auto pageRouterManager = weak.Upgrade();
473                 CHECK_NULL_VOID(pageRouterManager);
474                 taskExecutor->PostTask(
475                     [pageRouterManager, target, params, mode, errorCallback]() {
476                         pageRouterManager->PushOhmUrl(target, params, mode, errorCallback);
477                     },
478                     TaskExecutor::TaskType::JS);
479             };
480 
481         auto silentInstallErrorCallBack =
482             [errorCallback, taskExecutor, instanceId](
483                 int32_t errorCode, const std::string& errorMsg) {
484                 ContainerScope scope(instanceId);
485                 taskExecutor->PostTask(
486                     [errorCallback, errorCode, errorMsg]() {
487                         errorCallback(errorMsg, errorCode);
488                     },
489                     TaskExecutor::TaskType::JS);
490             };
491 
492         pageUrlChecker->LoadPageUrl(target.url, callback, silentInstallErrorCallBack);
493         return;
494     }
495     if (!manifestParser_) {
496         LOGE("the router manifest parser is null.");
497         return;
498     }
499     if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
500         LOGE("router stack size is larger than max size 32.");
501         return;
502     }
503     std::string url = target.url;
504     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(url);
505     LOGD("router.Push pagePath = %{private}s", pagePath.c_str());
506     if (pagePath.empty()) {
507         LOGE("[Engine Log] this uri not support in route push.");
508         if (errorCallback != nullptr) {
509             errorCallback("The uri of router is not exist.", Framework::ERROR_CODE_URI_ERROR);
510         }
511         return;
512     }
513     if (errorCallback != nullptr) {
514         errorCallback("", Framework::ERROR_CODE_NO_ERROR);
515     }
516     CleanPageOverlay();
517 
518     if (mode == RouterMode::SINGLE) {
519         auto pageInfo = FindPageInStack(url);
520         if (pageInfo.second) {
521             // find page in stack, move postion and update params.
522             MovePageToFront(pageInfo.first, pageInfo.second, params, false);
523             return;
524         }
525     }
526 
527     RouterPageInfo info { url };
528     info.path = pagePath;
529     LoadPage(GenerateNextPageId(), info, params);
530 }
531 
ReplaceOhmUrl(const RouterPageInfo & target,const std::string & params,RouterMode mode,const std::function<void (const std::string &,int32_t)> & errorCallback)532 void PageRouterManager::ReplaceOhmUrl(const RouterPageInfo& target, const std::string& params, RouterMode mode,
533     const std::function<void(const std::string&, int32_t)>& errorCallback)
534 {
535     std::string url = target.url;
536     std::string pagePath = url + ".js";
537     LOGD("router.Push pagePath = %{private}s", pagePath.c_str());
538 
539     PopPage("", false, false);
540 
541     if (mode == RouterMode::SINGLE) {
542         auto pageInfo = FindPageInStack(url);
543         if (pageInfo.second) {
544             // find page in stack, move postion and update params.
545             MovePageToFront(pageInfo.first, pageInfo.second, params, false, true, false);
546             return;
547         }
548     }
549 
550     RouterPageInfo info { url };
551     info.path = pagePath;
552     LoadPage(GenerateNextPageId(), info, params, false, false, false);
553 }
554 
StartReplace(const RouterPageInfo & target,const std::string & params,RouterMode mode,const std::function<void (const std::string &,int32_t)> & errorCallback)555 void PageRouterManager::StartReplace(const RouterPageInfo& target, const std::string& params, RouterMode mode,
556     const std::function<void(const std::string&, int32_t)>& errorCallback)
557 {
558     CHECK_RUN_ON(JS);
559     CleanPageOverlay();
560     RouterOptScope scope(this);
561     if (target.url.empty()) {
562         LOGE("router.Push uri is empty");
563         return;
564     }
565     if (target.url.substr(0, SUB_STR_LENGTH) == "@bundle") {
566         auto container = Container::Current();
567         CHECK_NULL_VOID(container);
568         auto pageUrlChecker = container->GetPageUrlChecker();
569         CHECK_NULL_VOID(pageUrlChecker);
570         auto instanceId = container->GetInstanceId();
571         auto taskExecutor = container->GetTaskExecutor();
572         CHECK_NULL_VOID(taskExecutor);
573         auto callback =
574             [weak = AceType::WeakClaim(this), target, params, mode, errorCallback, taskExecutor, instanceId]() {
575                 ContainerScope scope(instanceId);
576                 auto pageRouterManager = weak.Upgrade();
577                 CHECK_NULL_VOID(pageRouterManager);
578                 taskExecutor->PostTask(
579                     [pageRouterManager, target, params, mode, errorCallback]() {
580                         pageRouterManager->ReplaceOhmUrl(target, params, mode, errorCallback);
581                     },
582                     TaskExecutor::TaskType::JS);
583             };
584 
585         auto silentInstallErrorCallBack =
586             [errorCallback, taskExecutor, instanceId](
587                 int32_t errorCode, const std::string& errorMsg) {
588                 ContainerScope scope(instanceId);
589                 taskExecutor->PostTask(
590                     [errorCallback, errorCode, errorMsg]() {
591                         errorCallback(errorMsg, errorCode);
592                     },
593                     TaskExecutor::TaskType::JS);
594             };
595 
596         pageUrlChecker->LoadPageUrl(target.url, callback, silentInstallErrorCallBack);
597         return;
598     }
599     if (!manifestParser_) {
600         LOGE("the router manifest parser is null.");
601         return;
602     }
603     std::string url = target.url;
604     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(url);
605     LOGD("router.Push pagePath = %{private}s", pagePath.c_str());
606     if (pagePath.empty()) {
607         LOGE("[Engine Log] this uri not support in route push.");
608         if (errorCallback != nullptr) {
609             errorCallback("The uri of router is not exist.", Framework::ERROR_CODE_URI_ERROR_LITE);
610         }
611         return;
612     }
613     if (errorCallback != nullptr) {
614         errorCallback("", Framework::ERROR_CODE_NO_ERROR);
615     }
616 
617     PopPage("", false, false);
618 
619     if (mode == RouterMode::SINGLE) {
620         auto pageInfo = FindPageInStack(url);
621         if (pageInfo.second) {
622             // find page in stack, move position and update params.
623             MovePageToFront(pageInfo.first, pageInfo.second, params, false, true, false);
624             return;
625         }
626     }
627 
628     RouterPageInfo info { url };
629     info.path = pagePath;
630     LoadPage(GenerateNextPageId(), info, params, false, false, false);
631 }
632 
StartBack(const RouterPageInfo & target,const std::string & params,bool enableAlert)633 void PageRouterManager::StartBack(const RouterPageInfo& target, const std::string& params, bool enableAlert)
634 {
635     if (!enableAlert) {
636         CleanPageOverlay();
637     }
638     if (target.url.empty()) {
639         std::string pagePath;
640         size_t pageRouteSize = pageRouterStack_.size();
641         if (pageRouteSize < 2) {
642             LOGI("router stack is only one, back to desktop");
643             ExitToDesktop();
644             return;
645         }
646         // TODO: restore page operation.
647         PopPage(params, true, true);
648         return;
649     }
650 
651     if (target.url.substr(0, SUB_STR_LENGTH) == "@bundle") {
652         std::string url = target.url;
653         std::string pagePath = target.url + ".js";
654         LOGD("router.Push pagePath = %{private}s", pagePath.c_str());
655         if (pagePath.empty()) {
656             LOGE("[Engine Log] this uri not support in route push.");
657             return;
658         }
659         auto pageInfo = FindPageInStack(url);
660         if (pageInfo.second) {
661             // find page in stack, pop to specified index.
662             PopPageToIndex(pageInfo.first, params, true, true);
663             return;
664         }
665         LOGI("fail to find specified page to pop");
666         ExitToDesktop();
667         return;
668     }
669 
670     if (!manifestParser_) {
671         LOGE("the router manifest parser is null.");
672         return;
673     }
674     std::string url = target.url;
675     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(url);
676     LOGD("router.Push pagePath = %{private}s", pagePath.c_str());
677     if (pagePath.empty()) {
678         LOGE("[Engine Log] this uri not support in route push.");
679         return;
680     }
681     auto pageInfo = FindPageInStack(url);
682     if (pageInfo.second) {
683         // find page in stack, pop to specified index.
684         PopPageToIndex(pageInfo.first, params, true, true);
685         return;
686     }
687     LOGI("fail to find specified page to pop");
688 }
689 
BackCheckAlert(const RouterPageInfo & target,const std::string & params)690 void PageRouterManager::BackCheckAlert(const RouterPageInfo& target, const std::string& params)
691 {
692     RouterOptScope scope(this);
693     if (pageRouterStack_.empty()) {
694         LOGI("page route stack is empty");
695         return;
696     }
697     auto currentPage = pageRouterStack_.back().Upgrade();
698     CHECK_NULL_VOID(currentPage);
699     auto pagePattern = currentPage->GetPattern<PagePattern>();
700     CHECK_NULL_VOID(pagePattern);
701     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
702     CHECK_NULL_VOID(pageInfo);
703     if (pageInfo->GetAlertCallback()) {
704         ngBackUri_ = target;
705         backParam_ = params;
706 
707         auto pipelineContext = PipelineContext::GetCurrentContext();
708         auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
709         CHECK_NULL_VOID(overlayManager);
710         overlayManager->ShowDialog(
711             pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
712         return;
713     }
714 
715     StartBack(target, params);
716 }
717 
LoadPage(int32_t pageId,const RouterPageInfo & target,const std::string & params,bool,bool needHideLast,bool needTransition,const std::function<void (const std::string &,int32_t)> & errorCallback)718 void PageRouterManager::LoadPage(int32_t pageId, const RouterPageInfo& target, const std::string& params,
719     bool /*isRestore*/, bool needHideLast, bool needTransition,
720     const std::function<void(const std::string&, int32_t)>& errorCallback)
721 {
722     // TODO: isRestore function.
723     CHECK_RUN_ON(JS);
724     LOGI("PageRouterManager LoadPage[%{public}d]: %{public}s.", pageId, target.url.c_str());
725     auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, params);
726     auto pagePattern = AceType::MakeRefPtr<PagePattern>(entryPageInfo);
727     std::unordered_map<std::string, std::string> reportData { { "pageUrl", target.url } };
728     ResSchedReportScope reportScope("push_page", reportData);
729     auto pageNode =
730         FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
731     pageNode->SetHostPageId(pageId);
732     pageRouterStack_.emplace_back(pageNode);
733     auto result = loadJs_(target.path, errorCallback);
734     if (!result) {
735         LOGE("fail to load page file");
736         pageRouterStack_.pop_back();
737         return;
738     }
739     if (!OnPageReady(pageNode, needHideLast, needTransition)) {
740         LOGE("fail to mount page");
741         pageRouterStack_.pop_back();
742         return;
743     }
744     LOGI("PageRouterManager LoadPage[%{public}d]: %{public}s. success", pageId, target.url.c_str());
745 }
746 
LoadCard(int32_t pageId,const RouterPageInfo & target,const std::string & params,int64_t cardId,bool,bool needHideLast)747 void PageRouterManager::LoadCard(int32_t pageId, const RouterPageInfo& target, const std::string& params,
748     int64_t cardId, bool /*isRestore*/, bool needHideLast)
749 {
750     CHECK_RUN_ON(JS);
751     auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, params);
752     auto pagePattern = AceType::MakeRefPtr<PagePattern>(entryPageInfo);
753     auto pageNode =
754         FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
755     pageNode->SetHostPageId(pageId);
756     pageRouterStack_.emplace_back(pageNode);
757 
758     if (!loadCard_) {
759         LOGE("PageRouterManager loadCard_ is nullptr");
760         return;
761     }
762     auto result = loadCard_(target.url, cardId);
763     if (!result) {
764         LOGE("fail to load page file");
765         pageRouterStack_.pop_back();
766         return;
767     }
768 
769     if (!OnPageReady(pageNode, needHideLast, false, isCardRouter_, cardId)) {
770         LOGE("fail to mount page");
771         pageRouterStack_.pop_back();
772         return;
773     }
774 }
775 
MovePageToFront(int32_t index,const RefPtr<FrameNode> & pageNode,const std::string & params,bool needHideLast,bool forceShowCurrent,bool needTransition)776 void PageRouterManager::MovePageToFront(int32_t index, const RefPtr<FrameNode>& pageNode, const std::string& params,
777     bool needHideLast, bool forceShowCurrent, bool needTransition)
778 {
779     LOGD("MovePageToFront to index: %{public}d", index);
780     // update param first.
781     CHECK_NULL_VOID(pageNode);
782     auto pagePattern = pageNode->GetPattern<PagePattern>();
783     CHECK_NULL_VOID(pagePattern);
784     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
785     CHECK_NULL_VOID(pageInfo);
786 
787     if (index == static_cast<int32_t>(pageRouterStack_.size() - 1)) {
788         LOGD("already on the top");
789         if (!params.empty()) {
790             pageInfo->ReplacePageParams(params);
791         }
792         if (forceShowCurrent) {
793             pageNode->GetRenderContext()->ResetPageTransitionEffect();
794             StageManager::FirePageShow(pageNode, PageTransitionType::NONE);
795         }
796         return;
797     }
798     CHECK_NULL_VOID(pageNode);
799     auto container = Container::Current();
800     CHECK_NULL_VOID(container);
801     auto pipeline = container->GetPipelineContext();
802     CHECK_NULL_VOID(pipeline);
803     auto context = DynamicCast<NG::PipelineContext>(pipeline);
804     auto stageManager = context ? context->GetStageManager() : nullptr;
805     CHECK_NULL_VOID(stageManager);
806 
807     // clean pageNode on index position.
808     auto iter = pageRouterStack_.begin();
809     std::advance(iter, index);
810     auto last = pageRouterStack_.erase(iter);
811     // push pageNode to top.
812     pageRouterStack_.emplace_back(pageNode);
813     std::string tempParam;
814     if (!params.empty()) {
815         tempParam = pageInfo->ReplacePageParams(params);
816     }
817     if (!stageManager->MovePageToFront(pageNode, needHideLast, needTransition)) {
818         LOGE("fail to move page to front");
819         // restore position and param.
820         pageRouterStack_.pop_back();
821         pageRouterStack_.insert(last, pageNode);
822         if (!tempParam.empty()) {
823             pageInfo->ReplacePageParams(tempParam);
824         }
825     }
826 }
827 
FlushFrontend()828 void PageRouterManager::FlushFrontend()
829 {
830     auto currentPage = pageRouterStack_.back().Upgrade();
831     CHECK_NULL_VOID(currentPage);
832     auto customNode = DynamicCast<CustomNode>(currentPage->GetFirstChild());
833     CHECK_NULL_VOID(customNode);
834     customNode->FlushReload();
835 }
836 
PopPage(const std::string & params,bool needShowNext,bool needTransition)837 void PageRouterManager::PopPage(const std::string& params, bool needShowNext, bool needTransition)
838 {
839     CHECK_RUN_ON(JS);
840     if (pageRouterStack_.empty()) {
841         LOGE("page router stack size is illegal");
842         return;
843     }
844     if (needShowNext && (pageRouterStack_.size() == 1)) {
845         LOGE("page router stack size is only one, can not show next");
846         return;
847     }
848     auto topNode = pageRouterStack_.back();
849     pageRouterStack_.pop_back();
850     if (params.empty()) {
851         if (!OnPopPage(needShowNext, needTransition)) {
852             LOGE("fail to pop page");
853             pageRouterStack_.emplace_back(topNode);
854         }
855         return;
856     }
857 
858     // update param first.
859     auto nextNode = pageRouterStack_.back().Upgrade();
860     CHECK_NULL_VOID(nextNode);
861     auto pagePattern = nextNode->GetPattern<PagePattern>();
862     CHECK_NULL_VOID(pagePattern);
863     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
864     CHECK_NULL_VOID(pageInfo);
865     auto temp = pageInfo->ReplacePageParams(params);
866 
867     if (OnPopPage(needShowNext, needTransition)) {
868         return;
869     }
870     LOGE("fail to pop page");
871     // restore stack and pageParam.
872     pageRouterStack_.emplace_back(topNode);
873     pageInfo->ReplacePageParams(temp);
874 }
875 
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)876 void PageRouterManager::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
877 {
878     LOGD("PopPageToIndex to index: %{public}d", index);
879     std::list<WeakPtr<FrameNode>> temp;
880     std::swap(temp, pageRouterStack_);
881     auto iter = temp.begin();
882     for (int32_t current = 0; current <= index; ++current) {
883         pageRouterStack_.emplace_back(*iter);
884         iter++;
885     }
886     if (params.empty()) {
887         if (!OnPopPageToIndex(index, needShowNext, needTransition)) {
888             LOGE("fail to pop page to index");
889             std::swap(temp, pageRouterStack_);
890         }
891         return;
892     }
893 
894     // update param first.
895     auto nextNode = pageRouterStack_.back().Upgrade();
896     CHECK_NULL_VOID(nextNode);
897     auto pagePattern = nextNode->GetPattern<PagePattern>();
898     CHECK_NULL_VOID(pagePattern);
899     auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
900     CHECK_NULL_VOID(pageInfo);
901     auto tempParam = pageInfo->ReplacePageParams(params);
902 
903     if (OnPopPageToIndex(index, needShowNext, needTransition)) {
904         return;
905     }
906     LOGE("fail to pop page to index");
907     // restore stack and pageParam.
908     std::swap(temp, pageRouterStack_);
909     pageInfo->ReplacePageParams(tempParam);
910 }
911 
OnPageReady(const RefPtr<FrameNode> & pageNode,bool needHideLast,bool needTransition,bool isCardRouter,int64_t cardId)912 bool PageRouterManager::OnPageReady(
913     const RefPtr<FrameNode>& pageNode, bool needHideLast, bool needTransition, bool isCardRouter, int64_t cardId)
914 {
915     auto container = Container::Current();
916     CHECK_NULL_RETURN(container, false);
917     RefPtr<PipelineBase> pipeline;
918     if (isCardRouter) {
919         auto weak = container->GetCardPipeline(cardId);
920         pipeline = weak.Upgrade();
921         CHECK_NULL_RETURN(pipeline, false);
922     } else {
923         pipeline = container->GetPipelineContext();
924         CHECK_NULL_RETURN(pipeline, false);
925     }
926 
927     auto context = DynamicCast<NG::PipelineContext>(pipeline);
928     auto stageManager = context ? context->GetStageManager() : nullptr;
929     if (stageManager) {
930         return stageManager->PushPage(pageNode, needHideLast, needTransition);
931     }
932     LOGE("fail to push page due to stage manager is nullptr");
933     return false;
934 }
935 
OnPopPage(bool needShowNext,bool needTransition)936 bool PageRouterManager::OnPopPage(bool needShowNext, bool needTransition)
937 {
938     auto container = Container::Current();
939     CHECK_NULL_RETURN(container, false);
940     auto pipeline = container->GetPipelineContext();
941     CHECK_NULL_RETURN(pipeline, false);
942     auto context = DynamicCast<NG::PipelineContext>(pipeline);
943     auto stageManager = context ? context->GetStageManager() : nullptr;
944     if (stageManager) {
945         return stageManager->PopPage(needShowNext, needTransition);
946     }
947     LOGE("fail to pop page due to stage manager is nullptr");
948     return false;
949 }
950 
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)951 bool PageRouterManager::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
952 {
953     auto container = Container::Current();
954     CHECK_NULL_RETURN(container, false);
955     auto pipeline = container->GetPipelineContext();
956     CHECK_NULL_RETURN(pipeline, false);
957     auto context = DynamicCast<NG::PipelineContext>(pipeline);
958     auto stageManager = context ? context->GetStageManager() : nullptr;
959     if (stageManager) {
960         return stageManager->PopPageToIndex(index, needShowNext, needTransition);
961     }
962     LOGE("fail to pop page to index due to stage manager is nullptr");
963     return false;
964 }
965 
OnCleanPageStack()966 bool PageRouterManager::OnCleanPageStack()
967 {
968     auto container = Container::Current();
969     CHECK_NULL_RETURN(container, false);
970     auto pipeline = container->GetPipelineContext();
971     CHECK_NULL_RETURN(pipeline, false);
972     auto context = DynamicCast<NG::PipelineContext>(pipeline);
973     auto stageManager = context ? context->GetStageManager() : nullptr;
974     if (stageManager) {
975         return stageManager->CleanPageStack();
976     }
977     LOGE("fail to pop page to index due to stage manager is nullptr");
978     return false;
979 }
980 
CleanPageOverlay()981 void PageRouterManager::CleanPageOverlay()
982 {
983     auto container = Container::Current();
984     CHECK_NULL_VOID(container);
985     auto pipeline = container->GetPipelineContext();
986     CHECK_NULL_VOID(pipeline);
987     auto context = DynamicCast<NG::PipelineContext>(pipeline);
988     CHECK_NULL_VOID(context);
989     auto overlayManager = context->GetOverlayManager();
990     CHECK_NULL_VOID(overlayManager);
991     auto taskExecutor = context->GetTaskExecutor();
992     CHECK_NULL_VOID_NOLOG(taskExecutor);
993 
994     if (overlayManager->RemoveOverlay()) {
995         LOGI("clean page overlay.");
996     }
997 }
998 } // namespace OHOS::Ace::NG
999