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