• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "bridge/cj_frontend/frontend/cj_page_router.h"
17 
18 #include "bridge/cj_frontend/frontend/cj_frontend_abstract.h"
19 #include "bridge/cj_frontend/frontend/cj_page_loader.h"
20 #include "bridge/cj_frontend/runtime/cj_runtime_delegate.h"
21 #include "bridge/common/accessibility/accessibility_node_manager.h"
22 #include "bridge/declarative_frontend/view_stack_processor.h"
23 
24 namespace OHOS::Ace::Framework {
SetCjPageCallbackClassic(RefPtr<Framework::JsAcePage> page,NativeView * view)25 void SetCjPageCallbackClassic(RefPtr<Framework::JsAcePage> page, NativeView* view)
26 {
27     CHECK_NULL_VOID(view);
28     wptr<NativeView> weak = view;
29     CHECK_NULL_VOID(page);
30     page->SetDeclarativeOnPageAppearCallback([weak]() {
31         auto view = weak.promote();
32         if (view) {
33             view->FireOnShow();
34         }
35     });
36     page->SetDeclarativeOnPageDisAppearCallback([weak]() {
37         auto view = weak.promote();
38         if (view) {
39             view->FireOnHide();
40         }
41     });
42     page->SetDeclarativeOnBackPressCallback([weak]() {
43         auto view = weak.promote();
44         if (view) {
45             return view->FireOnBackPress();
46         }
47         return false;
48     });
49     page->SetDeclarativeOnPageRefreshCallback([weak]() {
50         auto view = weak.promote();
51         if (view) {
52             view->MarkNeedUpdate();
53         }
54     });
55     page->SetDeclarativeOnUpdateWithValueParamsCallback([weak](const std::string& params) {
56         auto view = weak.promote();
57         if (view && !params.empty()) {
58             view->ExecuteUpdateWithValueParams(params);
59         }
60     });
61 }
62 
LoadNativeViewClassic(NativeView * view)63 bool LoadNativeViewClassic(NativeView* view)
64 {
65     auto currentObj = Container::Current();
66     if (!currentObj) {
67         LOGE("LoadNativeView container is null");
68         return false;
69     }
70 
71     auto frontend = AceType::DynamicCast<CJFrontendAbstract>(currentObj->GetFrontend());
72     if (!frontend) {
73         LOGE("LoadNativeView frontend is null or not CJFrontend");
74         return false;
75     }
76     auto router = AceType::DynamicCast<CJPageRouter>(frontend->GetPageRouterManager());
77     if (!router) {
78         LOGE("LoadNativeView router is not CJPageRouter");
79         return false;
80     }
81     auto page = router->GetLoadingPage();
82     auto rootComponent = AceType::DynamicCast<Component>(view->CreateUI());
83     std::list<RefPtr<Component>> stackChildren;
84     stackChildren.emplace_back(rootComponent);
85     auto rootStackComponent = AceType::MakeRefPtr<StackComponent>(
86         Alignment::TOP_LEFT, StackFit::INHERIT, Overflow::OBSERVABLE, stackChildren);
87     rootStackComponent->SetMainStackSize(MainStackSize::MAX);
88     auto rootComposed = AceType::MakeRefPtr<ComposedComponent>("0", "root");
89     rootComposed->SetChild(rootStackComponent);
90     page->SetRootComponent(rootComposed);
91     auto pageTransitionComponent = ViewStackProcessor::GetInstance()->GetPageTransitionComponent();
92     ViewStackProcessor::GetInstance()->ClearPageTransitionComponent();
93     page->SetPageTransition(pageTransitionComponent);
94 
95     // We are done, tell to the JSAgePage
96     page->SetPageCreated();
97     SetCjPageCallbackClassic(page, view);
98     return true;
99 }
100 
PushLoadingPage(const RefPtr<JsAcePage> & page)101 void CJPageRouter::PushLoadingPage(const RefPtr<JsAcePage>& page)
102 {
103     loadingPage_ = page;
104 }
105 
OnShowCurrent()106 void CJPageRouter::OnShowCurrent()
107 {
108     auto topPage = GetTopPage();
109     CHECK_NULL_VOID(topPage);
110     topPage->FireDeclarativeOnPageAppearCallback();
111 }
112 
OnHideCurrent()113 void CJPageRouter::OnHideCurrent()
114 {
115     auto topPage = GetTopPage();
116     CHECK_NULL_VOID(topPage);
117     topPage->FireDeclarativeOnPageDisAppearCallback();
118 }
119 
AllowPopLastPage()120 bool CJPageRouter::AllowPopLastPage()
121 {
122     return true;
123 }
124 
LoadPage(int32_t pageId,const OHOS::Ace::CJPageRouterAbstract::RouterPageInfo & target,const std::string & params,bool isRestore,bool needHideLast,bool needTransition)125 void CJPageRouter::LoadPage(int32_t pageId, const OHOS::Ace::CJPageRouterAbstract::RouterPageInfo& target,
126     const std::string& params, bool isRestore, bool needHideLast, bool needTransition)
127 {
128     LOGI("LoadPage[%{public}d]: %{public}s.", pageId, target.url.c_str());
129     if (pageId < 0) {
130         LOGE("FrontendDelegateDeclarative, invalid page id");
131         return;
132     }
133     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
134     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, nullptr);
135     page->SetPageParams(params);
136     PushLoadingPage(page);
137     pageRouterStack_.emplace_back(page);
138 
139     page->SetFlushCallback([weak = AceType::WeakClaim(this), url = target.url](const RefPtr<JsAcePage>& acePage) {
140         CHECK_NULL_VOID(acePage);
141         auto delegate = weak.Upgrade();
142         CHECK_NULL_VOID(delegate);
143         delegate->FlushPage(acePage, url);
144     });
145     auto frontend = frontend_.Upgrade();
146     CHECK_NULL_VOID(frontend);
147     if (!CJRuntimeDelegate::GetInstance()->LoadAppEntry(target.url)) {
148         LOGE("Run CJ Page fail: %{public}s", target.url.c_str());
149         pageRouterStack_.pop_back();
150         return;
151     }
152     page->FlushCommands();
153     auto pipeline = AceType::DynamicCast<PipelineContext>(frontend->GetPipelineContext());
154     CHECK_NULL_VOID(pipeline);
155     pipeline->FlushFocus();
156     document->HandlePageLoadFinish();
157 }
158 
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> callback)159 void CJPageRouter::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)> callback) {}
160 
GetStackSize() const161 int32_t CJPageRouter::GetStackSize() const
162 {
163     return pageRouterStack_.size();
164 }
165 
GetParams() const166 std::string CJPageRouter::GetParams() const
167 {
168     auto topPage = GetTopPage();
169     if (!topPage) {
170         return "";
171     }
172     return topPage->GetPageParams();
173 }
174 
GetCurrentPageUrl()175 std::string CJPageRouter::GetCurrentPageUrl()
176 {
177     auto topPage = GetTopPage();
178     if (!topPage) {
179         return "";
180     }
181     return topPage->GetUrl();
182 }
183 
StartPush(const OHOS::Ace::CJPageRouterAbstract::RouterPageInfo & target,const std::string & params,OHOS::Ace::CJPageRouterAbstract::RouterMode mode)184 void CJPageRouter::StartPush(const OHOS::Ace::CJPageRouterAbstract::RouterPageInfo& target, const std::string& params,
185     OHOS::Ace::CJPageRouterAbstract::RouterMode mode)
186 {
187     ProcessGuard guard(this);
188     if (target.url.empty()) {
189         LOGE("router.Push uri is empty");
190         return;
191     }
192 
193     LoadPage(GenerateNextPageId(), target, params);
194 }
195 
StartPop()196 bool CJPageRouter::StartPop()
197 {
198     ProcessGuard guard(this);
199     if (pageRouterStack_.size() <= 1) {
200         // the last page.
201         return false;
202     }
203     auto topNode = pageRouterStack_.back();
204     pageRouterStack_.pop_back();
205     if (!OnPopPage(true, true)) {
206         LOGE("fail to pop page");
207         pageRouterStack_.emplace_back(topNode);
208         return false;
209     }
210     return true;
211 }
212 
StartReplace(const OHOS::Ace::CJPageRouterAbstract::RouterPageInfo & target,const std::string & params,OHOS::Ace::CJPageRouterAbstract::RouterMode mode)213 void CJPageRouter::StartReplace(const OHOS::Ace::CJPageRouterAbstract::RouterPageInfo& target,
214     const std::string& params, OHOS::Ace::CJPageRouterAbstract::RouterMode mode)
215 {
216     ProcessGuard guard(this);
217     if (target.url.empty()) {
218         LOGE("router.Push uri is empty");
219         return;
220     }
221     std::string url = target.url;
222 
223     PopPage("", false, false);
224 
225     RouterPageInfo info { url };
226     LoadPage(GenerateNextPageId(), info, params, false, false, false);
227 }
228 
BackCheckAlert(const RouterPageInfo & target,const std::string & params)229 void CJPageRouter::BackCheckAlert(const RouterPageInfo& target, const std::string& params)
230 {
231     {
232         ProcessGuard guard(this);
233         if (pageRouterStack_.empty()) {
234             LOGI("page route stack is empty");
235             return;
236         }
237         auto topPage = GetTopPage();
238         CHECK_NULL_VOID(topPage);
239 
240         if (!topPage->FireDeclarativeOnBackPressCallback()) {
241             return;
242         }
243     }
244 
245     StartPop();
246 }
247 
StartClean()248 void CJPageRouter::StartClean()
249 {
250     ProcessGuard guard(this);
251     if (pageRouterStack_.size() <= 1) {
252         LOGW("current page stack can not clean, %{public}d", static_cast<int32_t>(pageRouterStack_.size()));
253         return;
254     }
255     std::list<RefPtr<JsAcePage>> temp;
256     std::swap(temp, pageRouterStack_);
257     pageRouterStack_.emplace_back(temp.back());
258     if (!OnCleanPageStack()) {
259         LOGE("fail to clean page");
260         std::swap(temp, pageRouterStack_);
261     }
262 }
263 
PopPage(const std::string & params,bool needShowNext,bool needTransition)264 void CJPageRouter::PopPage(const std::string& params, bool needShowNext, bool needTransition)
265 {
266     if (pageRouterStack_.empty()) {
267         LOGE("page router stack size is illegal");
268         return;
269     }
270     if (needShowNext && (pageRouterStack_.size() == 1)) {
271         LOGE("page router stack size is only one, can not show next");
272         return;
273     }
274     auto topNode = pageRouterStack_.back();
275     pageRouterStack_.pop_back();
276 
277     if (params.empty()) {
278         if (!OnPopPage(needShowNext, needTransition)) {
279             LOGE("fail to pop page");
280             pageRouterStack_.emplace_back(topNode);
281         }
282         return;
283     }
284 
285     if (OnPopPage(needShowNext, needTransition)) {
286         return;
287     }
288     LOGE("fail to pop page");
289     // restore stack and pageParam.
290     pageRouterStack_.emplace_back(topNode);
291 }
292 
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)293 void CJPageRouter::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
294 {
295     LOGD("PopPageToIndex to index: %{public}d", index);
296     std::list<RefPtr<JsAcePage>> temp;
297     std::swap(temp, pageRouterStack_);
298     auto iter = temp.begin();
299     for (int32_t current = 0; current <= index; ++current) {
300         pageRouterStack_.emplace_back(*iter);
301         iter++;
302     }
303     if (params.empty()) {
304         if (!OnPopPageToIndex(index, needShowNext, needTransition)) {
305             LOGE("fail to pop page to index");
306             std::swap(temp, pageRouterStack_);
307         }
308         return;
309     }
310 
311     if (OnPopPageToIndex(index, needShowNext, needTransition)) {
312         return;
313     }
314     LOGE("fail to pop page to index");
315     // restore stack and pageParam.
316     std::swap(temp, pageRouterStack_);
317 }
318 
OnPopPage(bool needShowNext,bool needTransition)319 bool CJPageRouter::OnPopPage(bool needShowNext, bool needTransition)
320 {
321     auto frontend = frontend_.Upgrade();
322     CHECK_NULL_RETURN(frontend, false);
323     auto pipeline = AceType::DynamicCast<PipelineContext>(frontend->GetPipelineContext());
324     CHECK_NULL_RETURN(pipeline, false);
325     if (GetStackSize() == 1) {
326         if (!AllowPopLastPage()) {
327             return false;
328         }
329         OnHideCurrent();
330         return true;
331     }
332     if (!pipeline->CanPopPage()) {
333         return false;
334     }
335     OnHideCurrent();
336     pipeline->RemovePageTransitionListener(lastTransitionListener_);
337     lastTransitionListener_ = pipeline->AddPageTransitionListener(
338         [weak = WeakClaim(this), pageId = GetTopPage()->GetPageId()](
339             const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
340             auto delegate = weak.Upgrade();
341             if (delegate) {
342                 if (event == TransitionEvent::PUSH_END) {
343                     delegate->OnPopSuccess();
344                 }
345             }
346         });
347     return true;
348 }
349 
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)350 bool CJPageRouter::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
351 {
352     return false;
353 }
354 
OnCleanPageStack()355 bool CJPageRouter::OnCleanPageStack()
356 {
357     return true;
358 }
359 
OnPopSuccess()360 void CJPageRouter::OnPopSuccess()
361 {
362     SetCurrentPage();
363     OnShowCurrent();
364 }
365 
SetCurrentPage()366 void CJPageRouter::SetCurrentPage()
367 {
368     auto page = GetTopPage();
369     CHECK_NULL_VOID(page);
370     auto frontend = frontend_.Upgrade();
371     CHECK_NULL_VOID(frontend);
372     auto accessManager = frontend->GetAccessibilityManager();
373     CHECK_NULL_VOID(accessManager);
374     accessManager->SetVersion(AccessibilityVersion::JS_DECLARATIVE_VERSION);
375     auto nodeManager = DynamicCast<AccessibilityNodeManager>(accessManager);
376     nodeManager->SetRunningPage(page);
377     OnPageUpdate(page, false);
378 }
379 
FlushPage(const RefPtr<OHOS::Ace::Framework::JsAcePage> & page,const std::string & url)380 void CJPageRouter::FlushPage(const RefPtr<OHOS::Ace::Framework::JsAcePage>& page, const std::string& url)
381 {
382     if (page->FragmentCount() == 1) {
383         OnPageReady(page, url, pageRouterStack_.size() > 1);
384     } else {
385         OnPageUpdate(page, true);
386     }
387 }
388 
PostTask(std::function<void ()> callback,bool isUI)389 void CJPageRouter::PostTask(std::function<void()> callback, bool isUI)
390 {
391     auto frontend = frontend_.Upgrade();
392     CHECK_NULL_VOID(frontend);
393     auto executor = frontend->GetTaskExecutor();
394     CHECK_NULL_VOID(executor);
395     executor->PostTask(
396         std::move(callback), isUI ? TaskExecutor::TaskType::UI : TaskExecutor::TaskType::JS, "CJPageRouterPostTask");
397 }
398 
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool needHideLast)399 void CJPageRouter::OnPageReady(const RefPtr<JsAcePage>& page, const std::string& url, bool needHideLast)
400 {
401     loadingPage_ = nullptr;
402     auto frontend = frontend_.Upgrade();
403     CHECK_NULL_VOID(frontend);
404     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
405     page->PopAllCommands(*jsCommands);
406 
407     auto pipelineContext = AceType::DynamicCast<PipelineContext>(frontend->GetPipelineContext());
408     CHECK_NULL_VOID(pipelineContext);
409 
410     page->SetPipelineContext(pipelineContext);
411 
412     PostTask([weak = WeakClaim(this), jsCommands, url, page, pipelineContext, needHideLast] {
413         auto self = weak.Upgrade();
414         CHECK_NULL_VOID(self);
415         // Flush all JS commands.
416         for (const auto& command : *jsCommands) {
417             command->Execute(page);
418         }
419         // Just clear all dirty nodes.
420         page->ClearAllDirtyNodes();
421         if (page->GetDomDocument()) {
422             page->GetDomDocument()->HandleComponentPostBinding();
423         }
424         if (pipelineContext->GetAccessibilityManager()) {
425             pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
426         }
427 
428         if (!pipelineContext->CanPushPage()) {
429             LOGW("router push run in unexpected process");
430             return;
431         }
432         self->OnPrePageChange(page);
433         pipelineContext->RemovePageTransitionListener(self->lastTransitionListener_);
434         self->lastTransitionListener_ = pipelineContext->AddPageTransitionListener(
435             [weak, page](
436                 const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
437                 auto delegate = weak.Upgrade();
438                 if (event == TransitionEvent::PUSH_END) {
439                     delegate->OnPopSuccess();
440                 }
441             });
442         pipelineContext->PushPage(page->BuildPage(url), page->GetStageElement());
443     });
444 }
445 
OnPageUpdate(const RefPtr<OHOS::Ace::Framework::JsAcePage> & page,bool directExecute)446 void CJPageRouter::OnPageUpdate(const RefPtr<OHOS::Ace::Framework::JsAcePage>& page, bool directExecute)
447 {
448     auto frontend = frontend_.Upgrade();
449     CHECK_NULL_VOID(frontend);
450     auto pipeline = AceType::DynamicCast<PipelineContext>(frontend->GetPipelineContext());
451     CHECK_NULL_VOID(pipeline);
452 
453     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
454     page->PopAllCommands(*jsCommands);
455     WeakPtr<JsAcePage> weakPage = page;
456     WeakPtr<PipelineContext> weakContext = pipeline;
457     pipeline->AddPageUpdateTask(
458         [weakPage = std::move(weakPage), weakContext = std::move(weakContext), jsCommands] {
459             auto jsPage = weakPage.Upgrade();
460             auto context = weakContext.Upgrade();
461             if (!jsPage || !context) {
462                 LOGE("Page update failed. page or context is null.");
463                 return;
464             }
465             // Flush all JS commands.
466             for (const auto& command : *jsCommands) {
467                 command->Execute(jsPage);
468             }
469             if (jsPage->GetDomDocument()) {
470                 jsPage->GetDomDocument()->HandleComponentPostBinding();
471             }
472             auto accessibilityManager = context->GetAccessibilityManager();
473             if (accessibilityManager) {
474                 accessibilityManager->HandleComponentPostBinding();
475             }
476 
477             jsPage->ClearShowCommand();
478             std::vector<NodeId> dirtyNodes;
479             jsPage->PopAllDirtyNodes(dirtyNodes);
480             for (auto nodeId : dirtyNodes) {
481                 auto patchComponent = jsPage->BuildPagePatch(nodeId);
482                 if (patchComponent) {
483                     context->ScheduleUpdate(patchComponent);
484                 }
485             }
486         },
487         directExecute);
488 }
489 
OnPrePageChange(const RefPtr<OHOS::Ace::Framework::JsAcePage> & page)490 void CJPageRouter::OnPrePageChange(const RefPtr<OHOS::Ace::Framework::JsAcePage>& page)
491 {
492     CHECK_NULL_VOID(page);
493     auto document = page->GetDomDocument();
494     CHECK_NULL_VOID(document);
495     auto frontend = frontend_.Upgrade();
496     CHECK_NULL_VOID(frontend);
497     auto accessManager = frontend->GetAccessibilityManager();
498     CHECK_NULL_VOID(accessManager);
499     accessManager->SetRootNodeId(document->GetRootNodeId());
500 }
GetState(int32_t & index,std::string & name,std::string & path,std::string & params)501 void CJPageRouter::GetState(int32_t& index, std::string& name, std::string& path, std::string& params) {}
GetStateByIndex(int32_t & index,std::string & name,std::string & path,std::string & params)502 void CJPageRouter::GetStateByIndex(int32_t& index, std::string& name, std::string& path, std::string& params) {}
GetStateByUrl(const std::string & url)503 std::vector<CJPageRouterAbstract::RouterState> CJPageRouter::GetStateByUrl(const std::string& url)
504 {
505     return {};
506 }
StartPushPageWithCallback(const RouterPageInfo & target,const std::string & params)507 void CJPageRouter::StartPushPageWithCallback(const RouterPageInfo& target, const std::string& params) {}
StartReplacePageWithCallback(const RouterPageInfo & target,const std::string & params)508 void CJPageRouter::StartReplacePageWithCallback(const RouterPageInfo& target, const std::string& params) {}
BackCheckAlertIndex(int32_t index,const std::string & params)509 void CJPageRouter::BackCheckAlertIndex(int32_t index, const std::string& params) {}
DisableAlertBeforeBackPage()510 void CJPageRouter::DisableAlertBeforeBackPage() {}
511 } // namespace OHOS::Ace::Framework
512