• 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 "core/components_ng/pattern/stage/page_pattern.h"
17 
18 #include "base/log/jank_frame_report.h"
19 #include "base/perfmonitor/perf_constants.h"
20 #include "base/perfmonitor/perf_monitor.h"
21 #include "core/components_ng/base/observer_handler.h"
22 #include "core/components_ng/pattern/container_modal/container_modal_pattern.h"
23 #include "bridge/common/utils/engine_helper.h"
24 #include "bridge/declarative_frontend/ng/entry_page_info.h"
25 
26 namespace OHOS::Ace::NG {
27 
28 namespace {
29 constexpr int32_t INVALID_PAGE_INDEX = -1;
30 const int32_t MASK_DURATION = 350;
31 constexpr int32_t DEFAULT_ANIMATION_DURATION = 450;
32 std::string KEY_PAGE_TRANSITION_PROPERTY = "pageTransitionProperty";
33 constexpr float REMOVE_CLIP_SIZE = 10000.0f;
34 constexpr double HALF = 0.5;
35 constexpr double PARENT_PAGE_OFFSET = 0.2;
36 constexpr int32_t RELEASE_JSCHILD_DELAY_TIME = 50;
37 const Color MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
38 const Color DEFAULT_MASK_COLOR = Color::FromARGB(0, 0, 0, 0);
39 
IterativeAddToSharedMap(const RefPtr<UINode> & node,SharedTransitionMap & map)40 void IterativeAddToSharedMap(const RefPtr<UINode>& node, SharedTransitionMap& map)
41 {
42     const auto& children = node->GetChildren();
43     for (const auto& child : children) {
44         auto frameChild = AceType::DynamicCast<FrameNode>(child);
45         if (!frameChild) {
46             IterativeAddToSharedMap(child, map);
47             continue;
48         }
49         auto id = frameChild->GetRenderContext()->GetShareId();
50         if (!id.empty()) {
51             map[id] = frameChild;
52         }
53         IterativeAddToSharedMap(frameChild, map);
54     }
55 }
56 } // namespace
57 
OnAttachToFrameNode()58 void PagePattern::OnAttachToFrameNode()
59 {
60     auto host = GetHost();
61     CHECK_NULL_VOID(host);
62     MeasureType measureType = MeasureType::MATCH_PARENT;
63     auto container = Container::Current();
64     if (container && container->IsDynamicRender()) {
65         measureType = MeasureType::MATCH_CONTENT;
66     }
67     host->GetLayoutProperty()->UpdateMeasureType(measureType);
68     host->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
69     auto pipelineContext = host->GetContext();
70     CHECK_NULL_VOID(pipelineContext);
71     pipelineContext->AddWindowSizeChangeCallback(host->GetId());
72     pipelineContext->GetMemoryManager()->AddRecyclePageNode(host);
73 }
74 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & wrapper,const DirtySwapConfig &)75 bool PagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& wrapper, const DirtySwapConfig& /* config */)
76 {
77     if (isFirstLoad_) {
78         isFirstLoad_ = false;
79         if (firstBuildCallback_) {
80             firstBuildCallback_();
81             firstBuildCallback_ = nullptr;
82         }
83     }
84     return false;
85 }
86 
BeforeSyncGeometryProperties(const DirtySwapConfig & config)87 void PagePattern::BeforeSyncGeometryProperties(const DirtySwapConfig& config)
88 {
89     if (config.skipLayout || config.skipMeasure) {
90         return;
91     }
92     CHECK_NULL_VOID(dynamicPageSizeCallback_);
93     auto host = GetHost();
94     CHECK_NULL_VOID(host);
95     auto node = host->GetGeometryNode();
96     CHECK_NULL_VOID(node);
97     dynamicPageSizeCallback_(node->GetFrameSize());
98 }
99 
TriggerPageTransition(const std::function<void ()> & onFinish,PageTransitionType type)100 void PagePattern::TriggerPageTransition(const std::function<void()>& onFinish, PageTransitionType type)
101 {
102     auto host = GetHost();
103     CHECK_NULL_VOID(host);
104     if (pageTransitionFunc_) {
105         pageTransitionFunc_();
106     }
107     pageTransitionFinish_ = std::make_shared<std::function<void()>>(onFinish);
108     auto wrappedOnFinish = [weak = WeakClaim(this), sharedFinish = pageTransitionFinish_, type]() {
109         auto pattern = weak.Upgrade();
110         CHECK_NULL_VOID(pattern);
111         if (type == PageTransitionType::ENTER_PUSH || type == PageTransitionType::ENTER_POP) {
112             ACE_SCOPED_TRACE_COMMERCIAL("Router Page Transition End");
113             PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
114         }
115         auto host = pattern->GetHost();
116         CHECK_NULL_VOID(host);
117         if (sharedFinish == pattern->pageTransitionFinish_) {
118             // ensure this is exactly the finish callback saved in pagePattern,
119             // otherwise means new pageTransition started
120             pattern->FirePageTransitionFinish();
121             host->DeleteAnimatablePropertyFloat(KEY_PAGE_TRANSITION_PROPERTY);
122         }
123     };
124     auto effect = FindPageTransitionEffect(type);
125     if (effect && effect->GetUserCallback()) {
126         AnimationUtils::StopAnimation(currCustomAnimation_);
127         host->DeleteAnimatablePropertyFloat(KEY_PAGE_TRANSITION_PROPERTY);
128         RouteType routeType = (type == PageTransitionType::ENTER_POP || type == PageTransitionType::EXIT_POP)
129                                   ? RouteType::POP
130                                   : RouteType::PUSH;
131         host->CreateAnimatablePropertyFloat(KEY_PAGE_TRANSITION_PROPERTY, 0.0f,
132             [routeType, handler = effect->GetUserCallback()](const float& progress) { handler(routeType, progress); });
133         auto handler = effect->GetUserCallback();
134         handler(routeType, 0.0f);
135         AnimationOption option(effect->GetCurve(), effect->GetDuration());
136         option.SetDelay(effect->GetDelay());
137         option.SetOnFinishEvent(wrappedOnFinish);
138         option.SetAnimationInterface(AnimationInterface::PAGE_TRANSITION);
139         currCustomAnimation_ = AnimationUtils::StartAnimation(option, [weakPage = WeakPtr<FrameNode>(host)]() {
140             auto pageNode = weakPage.Upgrade();
141             CHECK_NULL_VOID(pageNode);
142             pageNode->UpdateAnimatablePropertyFloat(KEY_PAGE_TRANSITION_PROPERTY, 1.0f);
143         }, option.GetOnFinishEvent());
144         TriggerDefaultTransition(nullptr, type);
145         return;
146     }
147     TriggerDefaultTransition(wrappedOnFinish, type);
148 }
149 
ProcessAutoSave(const std::function<void ()> & onFinish,const std::function<void ()> & onUIExtNodeBindingCompleted)150 bool PagePattern::ProcessAutoSave(const std::function<void()>& onFinish,
151     const std::function<void()>& onUIExtNodeBindingCompleted)
152 {
153     auto host = GetHost();
154     CHECK_NULL_RETURN(host, false);
155     if (!host->NeedRequestAutoSave()) {
156         return false;
157     }
158     auto container = Container::Current();
159     CHECK_NULL_RETURN(container, false);
160     return container->RequestAutoSave(host, onFinish, onUIExtNodeBindingCompleted);
161 }
162 
ProcessHideState()163 void PagePattern::ProcessHideState()
164 {
165     auto host = GetHost();
166     CHECK_NULL_VOID(host);
167     host->SetActive(false);
168     host->NotifyVisibleChange(VisibleType::VISIBLE, VisibleType::INVISIBLE);
169     host->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
170     auto parent = host->GetAncestorNodeOfFrame(false);
171     CHECK_NULL_VOID(parent);
172     parent->MarkNeedSyncRenderTree();
173     parent->RebuildRenderContextTree();
174 }
175 
ProcessShowState()176 void PagePattern::ProcessShowState()
177 {
178     auto host = GetHost();
179     CHECK_NULL_VOID(host);
180     host->SetActive(true);
181     host->NotifyVisibleChange(VisibleType::INVISIBLE, VisibleType::VISIBLE);
182     host->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
183     auto parent = host->GetAncestorNodeOfFrame(false);
184     CHECK_NULL_VOID(parent);
185     auto context = NG::PipelineContext::GetCurrentContext();
186     CHECK_NULL_VOID(context);
187     auto manager = context->GetSafeAreaManager();
188     if (manager) {
189         auto safeArea = manager->GetSafeArea();
190         auto parentGlobalOffset = host->GetParentGlobalOffsetDuringLayout();
191         auto frame = host->GetPaintRectWithTransform() + parentGlobalOffset;
192         // if page's frameRect not fit current safeArea, need layout page again
193         if (!NearEqual(frame.GetY(), safeArea.top_.end)) {
194             host->MarkDirtyNode(manager->KeyboardSafeAreaEnabled() ? PROPERTY_UPDATE_LAYOUT : PROPERTY_UPDATE_MEASURE);
195         }
196         if (!NearEqual(frame.GetY() + frame.Height(), safeArea.bottom_.start)) {
197             host->MarkDirtyNode(manager->KeyboardSafeAreaEnabled() ? PROPERTY_UPDATE_LAYOUT : PROPERTY_UPDATE_MEASURE);
198         }
199     }
200     parent->MarkNeedSyncRenderTree();
201     parent->RebuildRenderContextTree();
202 }
203 
OnAttachToMainTree()204 void PagePattern::OnAttachToMainTree()
205 {
206 #if defined(ENABLE_SPLIT_MODE)
207     if (!needFireObserver_) {
208         return;
209     }
210 #endif
211     int32_t index = INVALID_PAGE_INDEX;
212     auto delegate = EngineHelper::GetCurrentDelegate();
213     if (delegate) {
214         index = delegate->GetCurrentPageIndex();
215         GetPageInfo()->SetPageIndex(index);
216     }
217     state_ = RouterPageState::ABOUT_TO_APPEAR;
218     UIObserverHandler::GetInstance().NotifyRouterPageStateChange(GetPageInfo(), state_);
219 }
220 
OnDetachFromMainTree()221 void PagePattern::OnDetachFromMainTree()
222 {
223 #if defined(ACE_STATIC)
224     FireOnNodeDisposeCallback();
225 #endif
226 #if defined(ENABLE_SPLIT_MODE)
227     if (!needFireObserver_) {
228         return;
229     }
230 #endif
231     state_ = RouterPageState::ABOUT_TO_DISAPPEAR;
232     UIObserverHandler::GetInstance().NotifyRouterPageStateChange(GetPageInfo(), state_);
233 }
234 
OnDetachFromFrameNode(FrameNode * frameNode)235 void PagePattern::OnDetachFromFrameNode(FrameNode* frameNode)
236 {
237     CHECK_NULL_VOID(frameNode);
238     auto pipelineContext = frameNode->GetContext();
239     CHECK_NULL_VOID(pipelineContext);
240     pipelineContext->RemoveWindowSizeChangeCallback(frameNode->GetId());
241     pipelineContext->GetMemoryManager()->RemoveRecyclePageNode(frameNode->GetId());
242 }
243 
OnWindowSizeChanged(int32_t,int32_t,WindowSizeChangeReason type)244 void PagePattern::OnWindowSizeChanged(int32_t /*width*/, int32_t /*height*/, WindowSizeChangeReason type)
245 {
246     if (type != WindowSizeChangeReason::ROTATION) {
247         return;
248     }
249     if (!isPageInTransition_) {
250         return;
251     }
252     auto page = GetHost();
253     CHECK_NULL_VOID(page);
254     auto renderContext = page->GetRenderContext();
255     CHECK_NULL_VOID(renderContext);
256     renderContext->RemoveClipWithRRect();
257 }
258 
OnShow(bool isFromWindow)259 void PagePattern::OnShow(bool isFromWindow)
260 {
261     // Do not invoke onPageShow unless the initialRender function has been executed.
262     CHECK_NULL_VOID(isRenderDone_);
263     CHECK_NULL_VOID(!isOnShow_);
264     auto context = NG::PipelineContext::GetCurrentContext();
265     CHECK_NULL_VOID(context);
266     auto container = Container::Current();
267     if (!container || !container->WindowIsShow()) {
268         LOGW("no need to trigger onPageShow callback when not in the foreground");
269         return;
270     }
271     NotifyPerfMonitorPageMsg(pageInfo_->GetFullPath(), container->GetBundleName());
272     if (pageInfo_) {
273         context->FirePageChanged(pageInfo_->GetPageId(), true);
274         NotifyNavigationLifecycle(true, isFromWindow);
275     }
276     UpdatePageParam();
277     isOnShow_ = true;
278 #if defined(ENABLE_SPLIT_MODE)
279     if (needFireObserver_) {
280         state_ = RouterPageState::ON_PAGE_SHOW;
281         UIObserverHandler::GetInstance().NotifyRouterPageStateChange(GetPageInfo(), state_);
282     }
283 #else
284     state_ = RouterPageState::ON_PAGE_SHOW;
285     UIObserverHandler::GetInstance().NotifyRouterPageStateChange(GetPageInfo(), state_);
286 #endif
287     JankFrameReport::GetInstance().StartRecord(pageInfo_->GetFullPath());
288     auto pageUrlChecker = container->GetPageUrlChecker();
289     if (pageUrlChecker != nullptr) {
290         pageUrlChecker->NotifyPageShow(pageInfo_->GetPageUrl());
291     }
292     if (visibilityChangeCallback_) {
293         visibilityChangeCallback_(true);
294     }
295     if (onPageShow_) {
296         onPageShow_();
297     }
298     if (!onHiddenChange_.empty()) {
299         FireOnHiddenChange(true);
300     }
301     RecordPageEvent(true);
302 }
303 
RecordPageEvent(bool isShow)304 void PagePattern::RecordPageEvent(bool isShow)
305 {
306     if (!Recorder::EventRecorder::Get().IsPageRecordEnable()) {
307         return;
308     }
309     auto entryPageInfo = DynamicCast<EntryPageInfo>(pageInfo_);
310     if (isShow) {
311         std::string param;
312         if (entryPageInfo) {
313             param = Recorder::EventRecorder::Get().IsPageParamRecordEnable() ? entryPageInfo->GetPageParams() : "";
314             entryPageInfo->SetShowTime(GetCurrentTimestamp());
315         }
316         Recorder::EventRecorder::Get().OnPageShow(
317             pageInfo_->GetPageUrl(), param, pageInfo_->GetRouteName().value_or(""));
318     } else {
319         int64_t duration = 0;
320         if (entryPageInfo && entryPageInfo->GetShowTime() > 0) {
321             duration = GetCurrentTimestamp() - entryPageInfo->GetShowTime();
322         }
323         Recorder::EventRecorder::Get().OnPageHide(
324             pageInfo_->GetPageUrl(), duration, pageInfo_->GetRouteName().value_or(""));
325     }
326 }
327 
OnHide(bool isFromWindow)328 void PagePattern::OnHide(bool isFromWindow)
329 {
330     CHECK_NULL_VOID(isOnShow_);
331     JankFrameReport::GetInstance().FlushRecord();
332     auto context = NG::PipelineContext::GetCurrentContext();
333     CHECK_NULL_VOID(context);
334     auto host = GetHost();
335     CHECK_NULL_VOID(host);
336     if (pageInfo_) {
337         NotifyNavigationLifecycle(false, isFromWindow);
338         context->FirePageChanged(pageInfo_->GetPageId(), false);
339     }
340     host->SetJSViewActive(false);
341     isOnShow_ = false;
342     host->SetAccessibilityVisible(false);
343 #if defined(ENABLE_SPLIT_MODE)
344     if (needFireObserver_) {
345         state_ = RouterPageState::ON_PAGE_HIDE;
346         UIObserverHandler::GetInstance().NotifyRouterPageStateChange(GetPageInfo(), state_);
347     }
348 #else
349     state_ = RouterPageState::ON_PAGE_HIDE;
350     UIObserverHandler::GetInstance().NotifyRouterPageStateChange(GetPageInfo(), state_);
351 #endif
352     auto container = Container::Current();
353     if (container) {
354         auto pageUrlChecker = container->GetPageUrlChecker();
355         // ArkTSCard container no SetPageUrlChecker
356         if (pageUrlChecker != nullptr) {
357             pageUrlChecker->NotifyPageHide(pageInfo_->GetPageUrl());
358         }
359     }
360     if (visibilityChangeCallback_) {
361         visibilityChangeCallback_(false);
362     }
363     if (onPageHide_) {
364         onPageHide_();
365     }
366     if (!onHiddenChange_.empty()) {
367         FireOnHiddenChange(false);
368     }
369     RecordPageEvent(false);
370 }
371 
OnBackPressed()372 bool PagePattern::OnBackPressed()
373 {
374     if (RemoveOverlay()) {
375         TAG_LOGI(AceLogTag::ACE_OVERLAY, "page removes it's overlay when on backpressed");
376         return true;
377     }
378     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) && isPageInTransition_) {
379         TAG_LOGI(AceLogTag::ACE_ROUTER, "page is in transition");
380         return true;
381     }
382     // if in page transition, do not set to ON_BACK_PRESS
383 #if defined(ENABLE_SPLIT_MODE)
384     if (needFireObserver_) {
385         state_ = RouterPageState::ON_BACK_PRESS;
386         UIObserverHandler::GetInstance().NotifyRouterPageStateChange(GetPageInfo(), state_);
387     }
388 #else
389     state_ = RouterPageState::ON_BACK_PRESS;
390     UIObserverHandler::GetInstance().NotifyRouterPageStateChange(GetPageInfo(), state_);
391 #endif
392     if (onBackPressed_) {
393         bool result = onBackPressed_();
394         CheckIsNeedForceExitWindow(result);
395         return result;
396     }
397     return false;
398 }
399 
BuildSharedTransitionMap()400 void PagePattern::BuildSharedTransitionMap()
401 {
402     auto host = GetHost();
403     CHECK_NULL_VOID(host);
404     sharedTransitionMap_.clear();
405     IterativeAddToSharedMap(host, sharedTransitionMap_);
406 }
407 
CheckIsNeedForceExitWindow(bool result)408 void PagePattern::CheckIsNeedForceExitWindow(bool result)
409 {
410     auto host = GetHost();
411     CHECK_NULL_VOID(host);
412     auto context = host->GetContext();
413     CHECK_NULL_VOID(context);
414     if (!context->GetInstallationFree() || !result) {
415         // if is not atommic service and result is false, don't process.
416         return;
417     }
418     auto stageManager = context->GetStageManager();
419     CHECK_NULL_VOID(stageManager);
420     int32_t pageSize =
421         stageManager->GetStageNode() ? static_cast<int32_t>(stageManager->GetStageNode()->GetChildren().size()) : 0;
422     if (pageSize != 1) {
423         return;
424     }
425     auto container = Container::Current();
426     CHECK_NULL_VOID(container);
427     if (container->IsUIExtensionWindow()) {
428         container->TerminateUIExtension();
429     } else {
430         auto windowManager = context->GetWindowManager();
431         CHECK_NULL_VOID(windowManager);
432         windowManager->WindowPerformBack();
433     }
434     TAG_LOGI(AceLogTag::ACE_ROUTER, "page onbackpress intercepted, exit window.");
435 }
436 
ReloadPage()437 void PagePattern::ReloadPage()
438 {
439     auto host = GetHost();
440     CHECK_NULL_VOID(host);
441     auto customNode = DynamicCast<CustomNodeBase>(host->GetFirstChild());
442     CHECK_NULL_VOID(customNode);
443     customNode->FireReloadFunction(true);
444 }
445 
FindPageTransitionEffect(PageTransitionType type)446 RefPtr<PageTransitionEffect> PagePattern::FindPageTransitionEffect(PageTransitionType type)
447 {
448     RefPtr<PageTransitionEffect> result;
449     for (auto iter = pageTransitionEffects_.rbegin(); iter != pageTransitionEffects_.rend(); ++iter) {
450         auto effect = *iter;
451         if (effect->CanFit(type)) {
452             result = effect;
453             break;
454         }
455     }
456     return result;
457 }
458 
ClearPageTransitionEffect()459 void PagePattern::ClearPageTransitionEffect()
460 {
461     pageTransitionEffects_.clear();
462 }
463 
GetTopTransition() const464 RefPtr<PageTransitionEffect> PagePattern::GetTopTransition() const
465 {
466     return pageTransitionEffects_.empty() ? nullptr : pageTransitionEffects_.back();
467 }
468 
AddPageTransition(const RefPtr<PageTransitionEffect> & effect)469 void PagePattern::AddPageTransition(const RefPtr<PageTransitionEffect>& effect)
470 {
471     pageTransitionEffects_.emplace_back(effect);
472 }
473 
AddJsAnimator(const std::string & animatorId,const RefPtr<Framework::AnimatorInfo> & animatorInfo)474 void PagePattern::AddJsAnimator(const std::string& animatorId, const RefPtr<Framework::AnimatorInfo>& animatorInfo)
475 {
476     CHECK_NULL_VOID(animatorInfo);
477     auto animator = animatorInfo->GetAnimator();
478     CHECK_NULL_VOID(animator);
479     animator->AttachScheduler(PipelineContext::GetCurrentContext());
480     jsAnimatorMap_[animatorId] = animatorInfo;
481 }
482 
GetJsAnimator(const std::string & animatorId)483 RefPtr<Framework::AnimatorInfo> PagePattern::GetJsAnimator(const std::string& animatorId)
484 {
485     auto iter = jsAnimatorMap_.find(animatorId);
486     if (iter != jsAnimatorMap_.end()) {
487         return iter->second;
488     }
489     return nullptr;
490 }
491 
SetFirstBuildCallback(std::function<void ()> && buildCallback)492 void PagePattern::SetFirstBuildCallback(std::function<void()>&& buildCallback)
493 {
494     if (isFirstLoad_) {
495         firstBuildCallback_ = std::move(buildCallback);
496     } else if (buildCallback) {
497         buildCallback();
498     }
499 }
500 
FirePageTransitionFinish()501 void PagePattern::FirePageTransitionFinish()
502 {
503     if (pageTransitionFinish_) {
504         auto onFinish = *pageTransitionFinish_;
505         pageTransitionFinish_ = nullptr;
506         if (onFinish) {
507             onFinish();
508         }
509     }
510 }
511 
StopPageTransition()512 void PagePattern::StopPageTransition()
513 {
514     auto host = GetHost();
515     CHECK_NULL_VOID(host);
516     auto property = host->GetAnimatablePropertyFloat(KEY_PAGE_TRANSITION_PROPERTY);
517     if (property) {
518         FirePageTransitionFinish();
519         return;
520     }
521     AnimationOption option(Curves::LINEAR, 0);
522     AnimationUtils::Animate(
523         option, [host]() { host->UpdateAnimatablePropertyFloat(KEY_PAGE_TRANSITION_PROPERTY, 0.0f); });
524     host->DeleteAnimatablePropertyFloat(KEY_PAGE_TRANSITION_PROPERTY);
525     FirePageTransitionFinish();
526 }
527 
BeforeCreateLayoutWrapper()528 void PagePattern::BeforeCreateLayoutWrapper()
529 {
530     auto host = GetHost();
531     CHECK_NULL_VOID(host);
532     auto pipeline = host->GetContext();
533     CHECK_NULL_VOID(pipeline);
534     // SafeArea already applied to AppBar (AtomicServicePattern)
535     if (pipeline->GetInstallationFree()) {
536         ACE_SCOPED_TRACE("[%s][self:%d] SafeArea already applied to AppBar", host->GetTag().c_str(), host->GetId());
537         return;
538     }
539     ContentRootPattern::BeforeCreateLayoutWrapper();
540     auto&& insets = host->GetLayoutProperty()->GetSafeAreaInsets();
541     CHECK_NULL_VOID(insets);
542     auto manager = pipeline->GetSafeAreaManager();
543     CHECK_NULL_VOID(manager);
544 }
545 
AvoidKeyboard() const546 bool PagePattern::AvoidKeyboard() const
547 {
548     auto host = GetHost();
549     CHECK_NULL_RETURN(host, false);
550     auto pipeline = host->GetContext();
551     CHECK_NULL_RETURN(pipeline, false);
552     auto safeAreaManager = pipeline->GetSafeAreaManager();
553     CHECK_NULL_RETURN(safeAreaManager, false);
554     return safeAreaManager->KeyboardSafeAreaEnabled();
555 }
556 
RemoveOverlay()557 bool PagePattern::RemoveOverlay()
558 {
559     CHECK_NULL_RETURN(overlayManager_, false);
560     if (overlayManager_->IsCurrentNodeProcessRemoveOverlay(GetHost(), false)) {
561         auto pipeline = PipelineContext::GetCurrentContext();
562         CHECK_NULL_RETURN(pipeline, false);
563         auto taskExecutor = pipeline->GetTaskExecutor();
564         CHECK_NULL_RETURN(taskExecutor, false);
565         return overlayManager_->RemoveOverlay(true);
566     }
567     return false;
568 }
569 
IsNeedCallbackBackPressed()570 bool PagePattern::IsNeedCallbackBackPressed()
571 {
572     CHECK_NULL_RETURN(overlayManager_, false);
573     return overlayManager_->IsCurrentNodeProcessRemoveOverlay(GetHost(), true);
574 }
575 
NotifyPerfMonitorPageMsg(const std::string & pageUrl,const std::string & bundleName)576 void PagePattern::NotifyPerfMonitorPageMsg(const std::string& pageUrl, const std::string& bundleName)
577 {
578     if (PerfMonitor::GetPerfMonitor() != nullptr) {
579         PerfMonitor::GetPerfMonitor()->SetPageUrl(pageUrl);
580         // The page contains only page url but not the page name
581         PerfMonitor::GetPerfMonitor()->SetPageName("");
582         PerfMonitor::GetPerfMonitor()->ReportPageShowMsg(pageUrl, bundleName, "");
583     }
584 }
585 
MarkDirtyOverlay()586 void PagePattern::MarkDirtyOverlay()
587 {
588     CHECK_NULL_VOID(overlayManager_);
589     overlayManager_->MarkDirtyOverlay();
590 }
591 
InitTransitionIn(const RefPtr<PageTransitionEffect> & effect,PageTransitionType type)592 void PagePattern::InitTransitionIn(const RefPtr<PageTransitionEffect>& effect, PageTransitionType type)
593 {
594     CHECK_NULL_VOID(effect);
595     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
596     CHECK_NULL_VOID(hostNode);
597     auto renderContext = hostNode->GetRenderContext();
598     CHECK_NULL_VOID(renderContext);
599     const auto& scaleOptions = effect->GetScaleEffect();
600     const auto& translateOptions = effect->GetTranslateEffect();
601     renderContext->UpdateTransformCenter(DimensionOffset(scaleOptions->centerX, scaleOptions->centerY));
602     renderContext->UpdateTransformScale(VectorF(scaleOptions->xScale, scaleOptions->yScale));
603     renderContext->UpdateTransformTranslate(translateOptions.value());
604     renderContext->UpdateOpacity(effect->GetOpacityEffect().value());
605     renderContext->ClipWithRRect(effect->GetPageTransitionRectF().value(), RadiusF(EdgeF(0.0f, 0.0f)));
606 }
607 
InitTransitionOut(const RefPtr<PageTransitionEffect> & effect,PageTransitionType type)608 void PagePattern::InitTransitionOut(const RefPtr<PageTransitionEffect> & effect, PageTransitionType type)
609 {
610     CHECK_NULL_VOID(effect);
611     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
612     CHECK_NULL_VOID(hostNode);
613     auto renderContext = hostNode->GetRenderContext();
614     CHECK_NULL_VOID(renderContext);
615     const auto& scaleOptions = effect->GetScaleEffect();
616     renderContext->UpdateTransformCenter(DimensionOffset(scaleOptions->centerX, scaleOptions->centerY));
617     renderContext->UpdateTransformScale(VectorF(1.0f, 1.0f));
618     renderContext->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
619     renderContext->UpdateOpacity(1.0);
620     renderContext->ClipWithRRect(effect->GetDefaultPageTransitionRectF().value(), RadiusF(EdgeF(0.0f, 0.0f)));
621 }
622 
GetDefaultPageTransition(PageTransitionType type)623 RefPtr<PageTransitionEffect> PagePattern::GetDefaultPageTransition(PageTransitionType type)
624 {
625     auto hostNode = GetHost();
626     CHECK_NULL_RETURN(hostNode, nullptr);
627     auto renderContext = hostNode->GetRenderContext();
628     CHECK_NULL_RETURN(renderContext, nullptr);
629     auto resultEffect = AceType::MakeRefPtr<PageTransitionEffect>(type, PageTransitionOption());
630     resultEffect->SetScaleEffect(ScaleOptions(1.0f, 1.0f, 1.0f, 0.5_pct, 0.5_pct));
631     TranslateOptions translate;
632     auto pipelineContext = PipelineContext::GetCurrentContext();
633     CHECK_NULL_RETURN(pipelineContext, nullptr);
634     auto safeAreaInsets = pipelineContext->GetSafeAreaWithoutProcess();
635     auto statusHeight = static_cast<float>(safeAreaInsets.top_.Length());
636     auto rect = renderContext->GetPaintRectWithoutTransform();
637     RectF defaultPageTransitionRectF = RectF(0.0f, -statusHeight, rect.Width(), REMOVE_CLIP_SIZE);
638     resultEffect->SetDefaultPageTransitionRectF(defaultPageTransitionRectF);
639     switch (type) {
640         case PageTransitionType::ENTER_PUSH:
641         case PageTransitionType::EXIT_POP:
642             UpdateEnterPushEffect(resultEffect, statusHeight);
643             break;
644         case PageTransitionType::ENTER_POP:
645             UpdateDefaultEnterPopEffect(resultEffect, statusHeight);
646             break;
647         case PageTransitionType::EXIT_PUSH:
648             UpdateExitPushEffect(resultEffect, statusHeight);
649             break;
650         default:
651             break;
652     }
653     resultEffect->SetOpacityEffect(1);
654     return resultEffect;
655 }
656 
UpdateDefaultEnterPopEffect(RefPtr<PageTransitionEffect> & effect,float statusHeight)657 void PagePattern::UpdateDefaultEnterPopEffect(RefPtr<PageTransitionEffect>& effect, float statusHeight)
658 {
659     CHECK_NULL_VOID(effect);
660     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
661     CHECK_NULL_VOID(hostNode);
662     auto renderContext = hostNode->GetRenderContext();
663     CHECK_NULL_VOID(renderContext);
664     auto rect = renderContext->GetPaintRectWithoutTransform();
665     effect->SetInitialBackgroundColor(MASK_COLOR);
666     effect->SetBackgroundColor(DEFAULT_MASK_COLOR);
667     TranslateOptions translate;
668     RectF pageTransitionRectF;
669     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
670         pageTransitionRectF =
671             RectF(rect.Width() * HALF, -statusHeight, rect.Width() * HALF, REMOVE_CLIP_SIZE);
672         translate.x = Dimension(rect.Width() * HALF);
673     } else {
674         pageTransitionRectF =
675             RectF(0.0f, -statusHeight, rect.Width() * PARENT_PAGE_OFFSET, REMOVE_CLIP_SIZE);
676         translate.x = Dimension(-rect.Width() * PARENT_PAGE_OFFSET);
677     }
678     effect->SetPageTransitionRectF(pageTransitionRectF);
679     effect->SetTranslateEffect(translate);
680 }
681 
UpdateEnterPushEffect(RefPtr<PageTransitionEffect> & effect,float statusHeight)682 void PagePattern::UpdateEnterPushEffect(RefPtr<PageTransitionEffect>& effect, float statusHeight)
683 {
684     CHECK_NULL_VOID(effect);
685     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
686     CHECK_NULL_VOID(hostNode);
687     auto renderContext = hostNode->GetRenderContext();
688     CHECK_NULL_VOID(renderContext);
689     auto rect = renderContext->GetPaintRectWithoutTransform();
690     effect->SetInitialBackgroundColor(DEFAULT_MASK_COLOR);
691     effect->SetBackgroundColor(DEFAULT_MASK_COLOR);
692     TranslateOptions translate;
693     RectF pageTransitionRectF;
694     RectF defaultPageTransitionRectF = RectF(0.0f, -statusHeight, rect.Width(), REMOVE_CLIP_SIZE);
695     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
696         pageTransitionRectF =
697             RectF(0.0f, -statusHeight, rect.Width() * PARENT_PAGE_OFFSET, REMOVE_CLIP_SIZE);
698         translate.x = Dimension(-rect.Width() * PARENT_PAGE_OFFSET);
699     } else {
700         pageTransitionRectF =
701             RectF(rect.Width() * HALF, -statusHeight, rect.Width() * HALF, REMOVE_CLIP_SIZE);
702         defaultPageTransitionRectF = RectF(0.0f, -statusHeight, rect.Width(), REMOVE_CLIP_SIZE);
703         translate.x = Dimension(rect.Width() * HALF);
704     }
705     effect->SetDefaultPageTransitionRectF(defaultPageTransitionRectF);
706     effect->SetPageTransitionRectF(pageTransitionRectF);
707     effect->SetTranslateEffect(translate);
708 }
709 
UpdateExitPushEffect(RefPtr<PageTransitionEffect> & effect,float statusHeight)710 void PagePattern::UpdateExitPushEffect(RefPtr<PageTransitionEffect>& effect, float statusHeight)
711 {
712     CHECK_NULL_VOID(effect);
713     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
714     CHECK_NULL_VOID(hostNode);
715     auto renderContext = hostNode->GetRenderContext();
716     CHECK_NULL_VOID(renderContext);
717     auto rect = renderContext->GetPaintRectWithoutTransform();
718     effect->SetInitialBackgroundColor(DEFAULT_MASK_COLOR);
719     effect->SetBackgroundColor(MASK_COLOR);
720     TranslateOptions translate;
721     RectF pageTransitionRectF;
722     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
723         pageTransitionRectF =
724             RectF(rect.Width() * HALF, -statusHeight, rect.Width() * HALF, REMOVE_CLIP_SIZE);
725         translate.x = Dimension(rect.Width() * HALF);
726     } else {
727         pageTransitionRectF =
728             RectF(0.0f, -statusHeight, rect.Width() * PARENT_PAGE_OFFSET, REMOVE_CLIP_SIZE);
729         translate.x = Dimension(-rect.Width() * PARENT_PAGE_OFFSET);
730     }
731     effect->SetPageTransitionRectF(pageTransitionRectF);
732     effect->SetTranslateEffect(translate);
733 }
734 
TransitionInFinish(const RefPtr<PageTransitionEffect> & effect,PageTransitionType type)735 void PagePattern::TransitionInFinish(const RefPtr<PageTransitionEffect>& effect, PageTransitionType type)
736 {
737     CHECK_NULL_VOID(effect);
738     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
739     CHECK_NULL_VOID(hostNode);
740     auto renderContext = hostNode->GetRenderContext();
741     CHECK_NULL_VOID(renderContext);
742     renderContext->UpdateTransformScale(VectorF(1.0f, 1.0f));
743     renderContext->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
744     renderContext->UpdateOpacity(1.0);
745     renderContext->ClipWithRRect(effect->GetDefaultPageTransitionRectF().value(), RadiusF(EdgeF(0.0f, 0.0f)));
746 }
747 
TransitionOutFinish(const RefPtr<PageTransitionEffect> & effect,PageTransitionType type)748 void PagePattern::TransitionOutFinish(const RefPtr<PageTransitionEffect>& effect, PageTransitionType type)
749 {
750     CHECK_NULL_VOID(effect);
751     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
752     CHECK_NULL_VOID(hostNode);
753     auto renderContext = hostNode->GetRenderContext();
754     CHECK_NULL_VOID(renderContext);
755     const auto& scaleOptions = effect->GetScaleEffect();
756     const auto& translateOptions = effect->GetTranslateEffect();
757     renderContext->UpdateTransformScale(VectorF(scaleOptions->xScale, scaleOptions->yScale));
758     renderContext->UpdateTransformTranslate(translateOptions.value());
759     renderContext->UpdateOpacity(effect->GetOpacityEffect().value());
760     renderContext->ClipWithRRect(effect->GetPageTransitionRectF().value(), RadiusF(EdgeF(0.0f, 0.0f)));
761 }
762 
MaskAnimation(const Color & initialBackgroundColor,const Color & backgroundColor)763 void PagePattern::MaskAnimation(const Color& initialBackgroundColor, const Color& backgroundColor)
764 {
765     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
766     CHECK_NULL_VOID(hostNode);
767     auto renderContext = hostNode->GetRenderContext();
768     CHECK_NULL_VOID(renderContext);
769     AnimationOption maskOption;
770     maskOption.SetCurve(Curves::FRICTION);
771     maskOption.SetDuration(MASK_DURATION);
772     renderContext->SetActualForegroundColor(initialBackgroundColor);
773     AnimationUtils::OpenImplicitAnimation(maskOption, maskOption.GetCurve(), nullptr);
774     renderContext->SetActualForegroundColor(backgroundColor);
775     AnimationUtils::CloseImplicitAnimation();
776 }
777 
GetPageTransitionEffect(const RefPtr<PageTransitionEffect> & transition)778 RefPtr<PageTransitionEffect> PagePattern::GetPageTransitionEffect(const RefPtr<PageTransitionEffect>& transition)
779 {
780     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
781     CHECK_NULL_RETURN(hostNode, nullptr);
782     auto renderContext = hostNode->GetRenderContext();
783     CHECK_NULL_RETURN(renderContext, nullptr);
784     auto resultEffect = AceType::MakeRefPtr<PageTransitionEffect>(
785         transition->GetPageTransitionType(), transition->GetPageTransitionOption());
786     resultEffect->SetScaleEffect(
787         transition->GetScaleEffect().value_or(ScaleOptions(1.0f, 1.0f, 1.0f, 0.5_pct, 0.5_pct)));
788     TranslateOptions translate;
789     auto rect = renderContext->GetPaintRectWithoutTransform();
790     auto context = PipelineContext::GetCurrentContext();
791     CHECK_NULL_RETURN(context, nullptr);
792     auto safeAreaInsets = context->GetSafeAreaWithoutProcess();
793     auto statusHeight = static_cast<float>(safeAreaInsets.top_.Length());
794     RectF defaultPageTransitionRectF = RectF(0.0f, -statusHeight, rect.Width(), REMOVE_CLIP_SIZE);
795     // slide and translate, only one can be effective
796     if (transition->GetSlideEffect().has_value()) {
797         SlideTransitionEffect(transition->GetSlideEffect().value(), rect, translate);
798     } else if (transition->GetTranslateEffect().has_value()) {
799         const auto& translateOptions = transition->GetTranslateEffect();
800         translate.x = Dimension(translateOptions->x.ConvertToPxWithSize(rect.Width()));
801         translate.y = Dimension(translateOptions->y.ConvertToPxWithSize(rect.Height()));
802         translate.z = Dimension(translateOptions->z.ConvertToPx());
803     }
804     resultEffect->SetTranslateEffect(translate);
805     resultEffect->SetOpacityEffect(transition->GetOpacityEffect().value_or(1));
806     resultEffect->SetPageTransitionRectF(RectF(0.0f, -statusHeight, rect.Width(), REMOVE_CLIP_SIZE));
807     resultEffect->SetDefaultPageTransitionRectF(defaultPageTransitionRectF);
808     resultEffect->SetInitialBackgroundColor(DEFAULT_MASK_COLOR);
809     resultEffect->SetBackgroundColor(DEFAULT_MASK_COLOR);
810     return resultEffect;
811 }
812 
SlideTransitionEffect(const SlideEffect & effect,const RectF & rect,TranslateOptions & translate)813 void PagePattern::SlideTransitionEffect(const SlideEffect& effect, const RectF& rect, TranslateOptions& translate)
814 {
815     switch (effect) {
816         case SlideEffect::LEFT:
817             translate.x = Dimension(-rect.Width());
818             break;
819         case SlideEffect::RIGHT:
820             translate.x = Dimension(rect.Width());
821             break;
822         case SlideEffect::BOTTOM:
823             translate.y = Dimension(rect.Height());
824             break;
825         case SlideEffect::TOP:
826             translate.y = Dimension(-rect.Height());
827             break;
828         case SlideEffect::START:
829             if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
830                 translate.x = Dimension(rect.Width());
831                 break;
832             }
833             translate.x = Dimension(-rect.Width());
834             break;
835         case SlideEffect::END:
836             if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
837                 translate.x = Dimension(-rect.Width());
838                 break;
839             }
840             translate.x = Dimension(rect.Width());
841             break;
842         default:
843             break;
844     }
845 }
846 
ResetPageTransitionEffect()847 void PagePattern::ResetPageTransitionEffect()
848 {
849     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
850     CHECK_NULL_VOID(hostNode);
851     auto renderContext = hostNode->GetRenderContext();
852     CHECK_NULL_VOID(renderContext);
853     renderContext->UpdateTransformTranslate({0.0f, 0.0f, 0.0f});
854     renderContext->RemoveClipWithRRect();
855     MaskAnimation(DEFAULT_MASK_COLOR, DEFAULT_MASK_COLOR);
856 }
857 
RemoveJsChildImmediately(const RefPtr<FrameNode> & page,PageTransitionType transactionType)858 void PagePattern::RemoveJsChildImmediately(const RefPtr<FrameNode>& page, PageTransitionType transactionType)
859 {
860     if (!CheckEnableCustomNodeDel()) {
861         return;
862     }
863 
864     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
865         return;
866     }
867 
868     if (transactionType != PageTransitionType::EXIT_POP) {
869         return;
870     }
871 
872     auto effect = FindPageTransitionEffect(transactionType);
873     if (effect && effect->GetUserCallback()) {
874         return;
875     }
876 
877     if (page->HasSkipNode()) {
878         return;
879     }
880 
881     auto taskExecutor = Container::CurrentTaskExecutor();
882     CHECK_NULL_VOID(taskExecutor);
883     taskExecutor->PostDelayedTask(
884         [weak = WeakPtr<FrameNode>(page)]() {
885             auto page = weak.Upgrade();
886             CHECK_NULL_VOID(page);
887             page->SetDestroying();
888         }, TaskExecutor::TaskType::UI, RELEASE_JSCHILD_DELAY_TIME, "ArkUIRemoveJsChild");
889 }
890 
FinishOutPage(const int32_t animationId,PageTransitionType type)891 void PagePattern::FinishOutPage(const int32_t animationId, PageTransitionType type)
892 {
893     auto outPage = AceType::DynamicCast<FrameNode>(GetHost());
894     CHECK_NULL_VOID(outPage);
895     outPage->SetNodeFreeze(false);
896     if (animationId_ != animationId) {
897         TAG_LOGI(AceLogTag::ACE_ROUTER, "animation id is different");
898         return;
899     }
900     outPage->GetOrCreateEventHub<EventHub>()->SetEnabled(true);
901     if (type != PageTransitionType::EXIT_PUSH && type != PageTransitionType::EXIT_POP) {
902         TAG_LOGI(AceLogTag::ACE_ROUTER, "current transition type is invalid");
903         return;
904     }
905     TAG_LOGI(AceLogTag::ACE_ROUTER, "%{public}s finish out page transition.", GetPageUrl().c_str());
906     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
907         FocusViewHide();
908     }
909 
910     if (outPage->IsInDestroying()) {
911         outPage->SetDestroying(false, false);
912     }
913     auto context = PipelineContext::GetCurrentContext();
914     CHECK_NULL_VOID(context);
915     if (type == PageTransitionType::EXIT_POP || isNeedRemove_) {
916         auto stageNode = outPage->GetParent();
917         CHECK_NULL_VOID(stageNode);
918         stageNode->RemoveChild(outPage);
919         stageNode->RebuildRenderContextTree();
920         context->RequestFrame();
921         return;
922     }
923     isPageInTransition_ = false;
924     ProcessHideState();
925     context->MarkNeedFlushMouseEvent();
926     auto stageManager = context->GetStageManager();
927     CHECK_NULL_VOID(stageManager);
928     stageManager->SetStageInTrasition(false);
929     ResetPageTransitionEffect();
930 }
931 
FinishInPage(const int32_t animationId,PageTransitionType type)932 void PagePattern::FinishInPage(const int32_t animationId, PageTransitionType type)
933 {
934     auto inPage = AceType::DynamicCast<FrameNode>(GetHost());
935     CHECK_NULL_VOID(inPage);
936     inPage->SetNodeFreeze(false);
937     if (animationId_ != animationId) {
938         TAG_LOGI(AceLogTag::ACE_ROUTER, "animation id in inPage is invalid");
939         return;
940     }
941     inPage->GetOrCreateEventHub<EventHub>()->SetEnabled(true);
942     if (type != PageTransitionType::ENTER_PUSH && type != PageTransitionType::ENTER_POP) {
943         TAG_LOGI(AceLogTag::ACE_ROUTER, "inPage transition type is invalid");
944         return;
945     }
946     TAG_LOGI(AceLogTag::ACE_ROUTER, "%{public}s finish inPage transition.", GetPageUrl().c_str());
947     isPageInTransition_ = false;
948     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
949         FocusViewShow();
950     }
951     auto context = PipelineContext::GetCurrentContext();
952     CHECK_NULL_VOID(context);
953     context->MarkNeedFlushMouseEvent();
954     ResetPageTransitionEffect();
955     auto stageManager = context->GetStageManager();
956     CHECK_NULL_VOID(stageManager);
957     stageManager->SetStageInTrasition(false);
958 }
959 
TriggerDefaultTransition(const std::function<void ()> & onFinish,PageTransitionType type)960 void PagePattern::TriggerDefaultTransition(const std::function<void()>& onFinish, PageTransitionType type)
961 {
962     bool transitionIn = true;
963     if (type == PageTransitionType::ENTER_PUSH || type == PageTransitionType::ENTER_POP) {
964         transitionIn = true;
965     } else if (type == PageTransitionType::EXIT_PUSH || type == PageTransitionType::EXIT_POP) {
966         transitionIn = false;
967     } else {
968         return;
969     }
970     auto transition = FindPageTransitionEffect(type);
971     RefPtr<PageTransitionEffect> effect;
972     AnimationOption option;
973     UpdateAnimationOption(transition, effect, option, type);
974     option.SetOnFinishEvent(onFinish);
975     option.SetAnimationInterface(AnimationInterface::PAGE_TRANSITION);
976     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
977     CHECK_NULL_VOID(hostNode);
978     auto pipelineContext = hostNode->GetContext();
979     CHECK_NULL_VOID(pipelineContext);
980     auto stageManager = pipelineContext->GetStageManager();
981     CHECK_NULL_VOID(stageManager);
982     if (transitionIn) {
983         InitTransitionIn(effect, type);
984         auto animation = AnimationUtils::StartAnimation(option, [weakPattern = WeakClaim(this), effect, type]() {
985             auto pattern = weakPattern.Upgrade();
986             CHECK_NULL_VOID(pattern);
987             pattern->TransitionInFinish(effect, type);
988         }, option.GetOnFinishEvent());
989         stageManager->AddAnimation(animation, type == PageTransitionType::ENTER_PUSH);
990         MaskAnimation(effect->GetInitialBackgroundColor().value(), effect->GetBackgroundColor().value());
991         return;
992     }
993     InitTransitionOut(effect, type);
994     auto animation = AnimationUtils::StartAnimation(option, [weakPattern = WeakClaim(this), effect, type]() {
995         auto pagePattern = weakPattern.Upgrade();
996         CHECK_NULL_VOID(pagePattern);
997         pagePattern->TransitionOutFinish(effect, type);
998     }, option.GetOnFinishEvent());
999     stageManager->AddAnimation(animation, type == PageTransitionType::ENTER_POP);
1000     MaskAnimation(effect->GetInitialBackgroundColor().value(), effect->GetBackgroundColor().value());
1001 }
1002 
UpdateAnimationOption(const RefPtr<PageTransitionEffect> & transition,RefPtr<PageTransitionEffect> & effect,AnimationOption & option,PageTransitionType type)1003 void PagePattern::UpdateAnimationOption(const RefPtr<PageTransitionEffect>& transition,
1004     RefPtr<PageTransitionEffect>& effect, AnimationOption& option, PageTransitionType type)
1005 {
1006     if (transition) {
1007         effect = GetPageTransitionEffect(transition);
1008         option.SetCurve(transition->GetCurve());
1009         option.SetDuration(transition->GetDuration());
1010         option.SetDelay(transition->GetDelay());
1011         return;
1012     }
1013     effect = GetDefaultPageTransition(type);
1014     const RefPtr<InterpolatingSpring> springCurve =
1015         AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 342.0f, 37.0f);
1016     auto host = GetHost();
1017     CHECK_NULL_VOID(host);
1018     auto pipeline = host->GetContext();
1019     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
1020         CHECK_NULL_VOID(pipeline);
1021         auto appTheme = pipeline->GetTheme<AppTheme>();
1022         CHECK_NULL_VOID(appTheme);
1023         float defaultAmplitudeRatio = appTheme->GetPageTransitionAmplitudeRatio();
1024         springCurve->UpdateMinimumAmplitudeRatio(defaultAmplitudeRatio);
1025     }
1026     option.SetCurve(springCurve);
1027     option.SetDuration(DEFAULT_ANIMATION_DURATION);
1028 #ifdef QUICK_PUSH_TRANSITION
1029     if (pipeline) {
1030         const int32_t nanoToMilliSeconds = 1000000;
1031         const int32_t minTransitionDuration = DEFAULT_ANIMATION_DURATION / 2;
1032         const int32_t frameDelayTime = 32;
1033         int32_t startDelayTime =
1034             static_cast<int32_t>(pipeline->GetTimeFromExternalTimer() - pipeline->GetLastTouchTime()) /
1035             nanoToMilliSeconds;
1036         startDelayTime = std::max(0, startDelayTime);
1037         int32_t delayedDuration = DEFAULT_ANIMATION_DURATION > startDelayTime
1038                                       ? DEFAULT_ANIMATION_DURATION - startDelayTime
1039                                       : DEFAULT_ANIMATION_DURATION;
1040         delayedDuration = std::max(minTransitionDuration, delayedDuration - frameDelayTime);
1041         LOGI("Use quick push delayedDuration:%{public}d", delayedDuration);
1042         option.SetDuration(delayedDuration);
1043     }
1044 #endif
1045 }
1046 
NotifyNavigationLifecycle(bool isShow,bool isFromWindow)1047 void PagePattern::NotifyNavigationLifecycle(bool isShow, bool isFromWindow)
1048 {
1049     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
1050     CHECK_NULL_VOID(hostNode);
1051     auto context = hostNode->GetContextRefPtr();
1052     CHECK_NULL_VOID(context);
1053     auto navigationManager = context->GetNavigationManager();
1054     CHECK_NULL_VOID(navigationManager);
1055     NavDestinationActiveReason activeReason = isFromWindow ? NavDestinationActiveReason::APP_STATE_CHANGE
1056         : NavDestinationActiveReason::TRANSITION;
1057     NavDestinationLifecycle lifecycle = isShow ? NavDestinationLifecycle::ON_ACTIVE
1058         : NavDestinationLifecycle::ON_INACTIVE;
1059     navigationManager->FireNavigationLifecycle(hostNode, static_cast<int32_t>(lifecycle),
1060         static_cast<int32_t>(activeReason));
1061 }
1062 
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)1063 WeakPtr<FocusHub> PagePattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
1064 {
1065     auto curFocus = currentFocusNode.Upgrade();
1066     CHECK_NULL_RETURN(curFocus, nullptr);
1067     auto curFrame = curFocus->GetFrameNode();
1068     CHECK_NULL_RETURN(curFrame, nullptr);
1069     auto context = NG::PipelineContext::GetCurrentContext();
1070     CHECK_NULL_RETURN(context, nullptr);
1071     auto root = context->GetRootElement();
1072     CHECK_NULL_RETURN(root, nullptr);
1073     auto container = AceType::DynamicCast<FrameNode>(root->GetChildren().front());
1074     CHECK_NULL_RETURN(container && container->GetTag() == V2::CONTAINER_MODAL_ETS_TAG, nullptr);
1075     auto pattern = container->GetPattern<NG::ContainerModalPattern>();
1076     CHECK_NULL_RETURN(pattern, nullptr);
1077     auto toolBarRow = pattern->GetCustomTitleRow();
1078     CHECK_NULL_RETURN(toolBarRow, nullptr);
1079     auto toolBarRowFocusHub = toolBarRow->GetFocusHub();
1080     CHECK_NULL_RETURN(toolBarRowFocusHub, nullptr);
1081 
1082     if (step == FocusStep::UP) {
1083         return toolBarRowFocusHub->GetHeadOrTailChild(true);
1084     } else if (step == FocusStep::TAB || step == FocusStep::SHIFT_TAB) {
1085         return toolBarRowFocusHub;
1086     }
1087     return nullptr;
1088 }
1089 
GetScopeFocusAlgorithm()1090 ScopeFocusAlgorithm PagePattern::GetScopeFocusAlgorithm()
1091 {
1092     auto focusAlgorithm = ScopeFocusAlgorithm(true, true, ScopeType::OTHERS);
1093     auto context = NG::PipelineContext::GetCurrentContext();
1094     CHECK_NULL_RETURN(context, focusAlgorithm);
1095     auto root = context->GetRootElement();
1096     CHECK_NULL_RETURN(root, focusAlgorithm);
1097     auto container = AceType::DynamicCast<FrameNode>(root->GetChildren().front());
1098     CHECK_NULL_RETURN(container && container->GetTag() == V2::CONTAINER_MODAL_ETS_TAG, focusAlgorithm);
1099     auto pattern = container->GetPattern<NG::ContainerModalPattern>();
1100     CHECK_NULL_RETURN(pattern && pattern->GetIsHaveToolBar(), focusAlgorithm);
1101     auto toolBarRow = pattern->GetCustomTitleRow();
1102     CHECK_NULL_RETURN(toolBarRow, focusAlgorithm);
1103     auto toolBarRowFocusHub = toolBarRow->GetFocusHub();
1104     CHECK_NULL_RETURN(toolBarRowFocusHub, focusAlgorithm);
1105     CHECK_NULL_RETURN(toolBarRowFocusHub->GetHeadOrTailChild(true), focusAlgorithm);
1106     focusAlgorithm.getNextFocusNode = [wp = WeakClaim(this)](FocusStep step, const WeakPtr<FocusHub>& currFocusNode,
1107                                           WeakPtr<FocusHub>& nextFocusNode) -> bool {
1108         auto page = wp.Upgrade();
1109         CHECK_NULL_RETURN(page, false);
1110         nextFocusNode = page->GetNextFocusNode(step, currFocusNode);
1111         return nextFocusNode.Upgrade() != currFocusNode.Upgrade();
1112     };
1113     return focusAlgorithm;
1114 }
1115 
1116 } // namespace OHOS::Ace::NG
1117