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