• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "core/components_ng/pattern/bubble/bubble_pattern.h"
16 
17 #include "base/subwindow/subwindow.h"
18 #include "base/subwindow/subwindow_manager.h"
19 #include "base/utils/utils.h"
20 #include "core/common/container.h"
21 #include "base/log/dump_log.h"
22 #include "core/common/container_scope.h"
23 #include "core/common/window_animation_config.h"
24 #include "core/components/common/properties/shadow_config.h"
25 #include "core/components/container_modal/container_modal_constants.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/base/ui_node.h"
28 #include "core/components_ng/pattern/bubble/bubble_layout_property.h"
29 #include "core/components_ng/pattern/bubble/bubble_render_property.h"
30 #include "core/components_ng/pattern/text/text_layout_property.h"
31 
32 namespace OHOS::Ace::NG {
33 namespace {
34 constexpr float VISIABLE_ALPHA = 1.0f;
35 constexpr float INVISIABLE_ALPHA = 0.0f;
36 constexpr int32_t ENTRY_ANIMATION_DURATION = 250;
37 constexpr int32_t EXIT_ANIMATION_DURATION = 100;
38 const Dimension INVISIABLE_OFFSET = 8.0_px;
39 } // namespace
40 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)41 bool BubblePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
42 {
43     if (skipMeasure && skipLayout) {
44         return false;
45     }
46     auto host = GetHost();
47     CHECK_NULL_RETURN(host, false);
48     auto paintProperty = host->GetPaintProperty<BubbleRenderProperty>();
49     CHECK_NULL_RETURN(paintProperty, false);
50     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
51     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
52     auto bubbleLayoutAlgorithm = DynamicCast<BubbleLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
53     CHECK_NULL_RETURN(bubbleLayoutAlgorithm, false);
54 
55     showArrow_ = bubbleLayoutAlgorithm->ShowArrow();
56     arrowPosition_ = bubbleLayoutAlgorithm->GetArrowPosition();
57     childOffset_ = bubbleLayoutAlgorithm->GetChildOffset();
58     childSize_ = bubbleLayoutAlgorithm->GetChildSize();
59     touchRegion_ = bubbleLayoutAlgorithm->GetTouchRegion();
60     hostWindowRect_ = bubbleLayoutAlgorithm->GetHostWindowRect();
61     targetOffset_ = bubbleLayoutAlgorithm->GetTargetOffset();
62     targetSize_ = bubbleLayoutAlgorithm->GetTargetSize();
63     arrowPlacement_ = bubbleLayoutAlgorithm->GetArrowPlacement();
64     clipPath_ = bubbleLayoutAlgorithm->GetClipPath();
65     clipFrameNode_ = bubbleLayoutAlgorithm->GetClipFrameNode();
66     arrowOffsetsFromClip_ = bubbleLayoutAlgorithm->GetArrowOffsetsFromClip();
67     arrowWidth_ = bubbleLayoutAlgorithm->GetArrowWidth();
68     arrowHeight_ = bubbleLayoutAlgorithm->GetArrowHeight();
69     border_ = bubbleLayoutAlgorithm->GetBorder();
70     dumpInfo_ = bubbleLayoutAlgorithm->GetDumpInfo();
71     arrowBuildPlacement_ = bubbleLayoutAlgorithm->GetArrowBuildPlacement();
72     paintProperty->UpdatePlacement(bubbleLayoutAlgorithm->GetArrowPlacement());
73     if (delayShow_) {
74         delayShow_ = false;
75         if (transitionStatus_ == TransitionStatus::INVISIABLE) {
76             StartEnteringAnimation(nullptr);
77         }
78     }
79     return true;
80 }
81 
OnModifyDone()82 void BubblePattern::OnModifyDone()
83 {
84     auto context = GetContext();
85     CHECK_NULL_VOID(context);
86     if (context->GetColorMode() != colorMode_ && !isCustomPopup_) {
87         colorMode_ = context->GetColorMode();
88         UpdateBubbleText();
89     }
90     UpdateAgingTextSize();
91     Pattern::OnModifyDone();
92     InitTouchEvent();
93 }
94 
AddPipelineCallBack()95 void BubblePattern::AddPipelineCallBack()
96 {
97     auto host = GetHost();
98     CHECK_NULL_VOID(host);
99     auto pipelineContext = host->GetContextRefPtr();
100     CHECK_NULL_VOID(pipelineContext);
101     pipelineContext->AddWindowSizeChangeCallback(host->GetId());
102     pipelineContext->AddWindowStateChangedCallback(host->GetId());
103 }
104 
OnAttachToFrameNode()105 void BubblePattern::OnAttachToFrameNode()
106 {
107     auto host = GetHost();
108     CHECK_NULL_VOID(host);
109     host->GetRenderContext()->SetClipToFrame(true);
110 
111     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
112     CHECK_NULL_VOID(targetNode);
113     auto pipelineContext = host->GetContextRefPtr();
114     CHECK_NULL_VOID(pipelineContext);
115     hasOnAreaChange_ = pipelineContext->HasOnAreaChangeNode(targetNode->GetId());
116     auto eventHub = targetNode->GetOrCreateEventHub<EventHub>();
117     CHECK_NULL_VOID(eventHub);
118     OnAreaChangedFunc onAreaChangedFunc = [popupNodeWk = WeakPtr<FrameNode>(host), weak = WeakClaim(this)](
119                                               const RectF& /* oldRect */, const OffsetF& /* oldOrigin */,
120                                               const RectF& /* rect */, const OffsetF& /* origin */) {
121         auto popupNode = popupNodeWk.Upgrade();
122         CHECK_NULL_VOID(popupNode);
123         popupNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
124         auto pattern = weak.Upgrade();
125         if (pattern) {
126             pattern->PopBubble(true);
127         }
128     };
129     eventHub->AddInnerOnAreaChangedCallback(host->GetId(), std::move(onAreaChangedFunc));
130 
131     halfFoldHoverCallbackId_ =
132         pipelineContext->RegisterHalfFoldHoverChangedCallback([weak = WeakClaim(this)](bool isHalfFoldHover) {
133             auto pattern = weak.Upgrade();
134             CHECK_NULL_VOID(pattern);
135             auto host = pattern->GetHost();
136             CHECK_NULL_VOID(host);
137             AnimationOption option;
138             auto curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(0.35f, 1.0f, 0.0f);
139             option.SetCurve(curve);
140             auto context = host->GetContext();
141             CHECK_NULL_VOID(context);
142             AnimationUtils::Animate(option, [host, context]() {
143                 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
144                 context->FlushUITasks();
145             }, nullptr, nullptr, host->GetContextRefPtr());
146         });
147 }
148 
OnDetachFromFrameNode(FrameNode * frameNode)149 void BubblePattern::OnDetachFromFrameNode(FrameNode* frameNode)
150 {
151     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
152     CHECK_NULL_VOID(pipeline);
153     pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
154     pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
155     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
156     CHECK_NULL_VOID(targetNode);
157     if (!hasOnAreaChange_) {
158         pipeline->RemoveOnAreaChangeNode(targetNode->GetId());
159     }
160     pipeline->UnRegisterHalfFoldHoverChangedCallback(halfFoldHoverCallbackId_);
161 }
162 
InitTouchEvent()163 void BubblePattern::InitTouchEvent()
164 {
165     auto host = GetHost();
166     CHECK_NULL_VOID(host);
167     auto hub = host->GetOrCreateEventHub<EventHub>();
168     CHECK_NULL_VOID(hub);
169     auto gestureHub = hub->GetOrCreateGestureEventHub();
170     CHECK_NULL_VOID(gestureHub);
171     if (touchEvent_) {
172         return;
173     }
174     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
175         auto pattern = weak.Upgrade();
176         if (pattern) {
177             pattern->HandleTouchEvent(info);
178         }
179     };
180     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
181     gestureHub->AddTouchEvent(touchEvent_);
182 }
183 
HandleTouchEvent(const TouchEventInfo & info)184 void BubblePattern::HandleTouchEvent(const TouchEventInfo& info)
185 {
186     if (info.GetTouches().empty()) {
187         return;
188     }
189     auto touchType = info.GetTouches().front().GetTouchType();
190     auto clickPos = info.GetTouches().front().GetLocalLocation();
191     if (touchType == TouchType::DOWN) {
192         HandleTouchDown(clickPos);
193     }
194 }
195 
HandleTouchDown(const Offset & clickPosition)196 void BubblePattern::HandleTouchDown(const Offset& clickPosition)
197 {
198     auto host = GetHost();
199     CHECK_NULL_VOID(host);
200     auto bubbleRenderProp = host->GetPaintProperty<BubbleRenderProperty>();
201     CHECK_NULL_VOID(bubbleRenderProp);
202     if (touchRegion_.IsInRegion(PointF(clickPosition.GetX(), clickPosition.GetY()))) {
203         return;
204     }
205     auto autoCancel = bubbleRenderProp->GetAutoCancel().value_or(true);
206     if (autoCancel) {
207         TAG_LOGD(AceLogTag::ACE_DIALOG, "handle popup touch down event");
208         if (!GetInteractiveDismiss()) {
209             return;
210         }
211         if (HasOnWillDismiss()) {
212             auto pipelineNg = host->GetContextRefPtr();
213             CHECK_NULL_VOID(pipelineNg);
214             auto overlayManager = pipelineNg->GetOverlayManager();
215             CHECK_NULL_VOID(overlayManager);
216             overlayManager->SetDismissPopupId(targetNodeId_);
217             CallOnWillDismiss(static_cast<int32_t>(DismissReason::TOUCH_OUTSIDE));
218             return;
219         }
220         PopBubble();
221     }
222 }
223 
RegisterButtonOnHover()224 void BubblePattern::RegisterButtonOnHover()
225 {
226     if (mouseEventInitFlag_) {
227         return;
228     }
229     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
230     CHECK_NULL_VOID(paintProps);
231     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
232     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
233     auto custom = paintProps->GetUseCustom().value_or(false);
234     if (custom) {
235         return;
236     }
237     if (!primaryButtonShow && !secondaryButtonShow) {
238         return;
239     }
240     auto buttonRowNode = GetButtonRowNode();
241     for (const auto& child : buttonRowNode->GetChildren()) {
242         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
243         CHECK_NULL_VOID(buttonNode);
244         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
245             return;
246         }
247         auto inputHub = buttonNode->GetOrCreateInputEventHub();
248         CHECK_NULL_VOID(inputHub);
249         auto mouseTask = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)](bool isHover) {
250             auto pattern = weak.Upgrade();
251             CHECK_NULL_VOID(pattern);
252             auto buttonNode = buttonNodeWK.Upgrade();
253             CHECK_NULL_VOID(buttonNode);
254             pattern->ButtonOnHover(isHover, buttonNode);
255         };
256         auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
257         inputHub->AddOnHoverEvent(mouseEvent);
258     }
259     mouseEventInitFlag_ = true;
260 }
261 
ButtonOnHover(bool isHover,const RefPtr<NG::FrameNode> & buttonNode)262 void BubblePattern::ButtonOnHover(bool isHover, const RefPtr<NG::FrameNode>& buttonNode)
263 {
264     auto renderContext = buttonNode->GetRenderContext();
265     CHECK_NULL_VOID(renderContext);
266     auto theme = GetPopupTheme();
267     CHECK_NULL_VOID(theme);
268     isHover_ = isHover;
269     auto hoverColor = theme->GetButtonHoverColor();
270     auto backgroundColor = theme->GetButtonBackgroundColor();
271     if (isHover) {
272         // normal to hover
273         Animation(renderContext, hoverColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
274     } else {
275         // hover to normal
276         Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
277     }
278 }
279 
RegisterButtonOnTouch()280 void BubblePattern::RegisterButtonOnTouch()
281 {
282     if (touchEventInitFlag_) {
283         return;
284     }
285     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
286     CHECK_NULL_VOID(paintProps);
287     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
288     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
289     auto custom = paintProps->GetUseCustom().value_or(false);
290     if (custom) {
291         return;
292     }
293     if (!primaryButtonShow && !secondaryButtonShow) {
294         return;
295     }
296 
297     auto buttonRowNode = GetButtonRowNode();
298     for (const auto& child : buttonRowNode->GetChildren()) {
299         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
300         CHECK_NULL_VOID(buttonNode);
301         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
302             return;
303         }
304         auto gestureHub = buttonNode->GetOrCreateGestureEventHub();
305         CHECK_NULL_VOID(gestureHub);
306         auto touchCallback = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)]
307             (const TouchEventInfo& info) {
308             auto pattern = weak.Upgrade();
309             CHECK_NULL_VOID(pattern);
310             auto buttonNode = buttonNodeWK.Upgrade();
311             CHECK_NULL_VOID(buttonNode);
312             pattern->ButtonOnPress(info, buttonNode);
313         };
314         auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
315         gestureHub->AddTouchEvent(touchEvent);
316     }
317     touchEventInitFlag_ = true;
318 }
319 
ButtonOnPress(const TouchEventInfo & info,const RefPtr<NG::FrameNode> & buttonNode)320 void BubblePattern::ButtonOnPress(const TouchEventInfo& info, const RefPtr<NG::FrameNode>& buttonNode)
321 {
322     if (info.GetTouches().empty()) {
323         return;
324     }
325     auto touchType = info.GetTouches().front().GetTouchType();
326     auto renderContext = buttonNode->GetRenderContext();
327     CHECK_NULL_VOID(renderContext);
328     auto theme = GetPopupTheme();
329     CHECK_NULL_VOID(theme);
330     auto pressColor = theme->GetButtonPressColor();
331     auto hoverColor = theme->GetButtonHoverColor();
332     auto backgroundColor = theme->GetButtonBackgroundColor();
333     if (touchType == TouchType::DOWN) {
334         if (isHover_) {
335             // hover to press
336             Animation(renderContext, pressColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
337         } else {
338             // normal to press
339             Animation(renderContext, pressColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
340         }
341     } else if (touchType == TouchType::UP) {
342         if (isHover_) {
343             // press to hover
344             Animation(renderContext, hoverColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
345         } else {
346             // press to normal
347             Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
348         }
349     }
350 }
351 
GetButtonRowNode()352 RefPtr<FrameNode> BubblePattern::GetButtonRowNode()
353 {
354     auto host = GetHost();
355     CHECK_NULL_RETURN(host, nullptr);
356     auto columnNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
357     CHECK_NULL_RETURN(columnNode, nullptr);
358     auto lastColumnNode = AceType::DynamicCast<FrameNode>(columnNode->GetLastChild());
359     CHECK_NULL_RETURN(lastColumnNode, nullptr);
360     auto buttonRowNode = AceType::DynamicCast<FrameNode>(lastColumnNode->GetLastChild());
361     CHECK_NULL_RETURN(buttonRowNode, nullptr);
362     if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
363         if (buttonRowNode->GetTag() != V2::ROW_ETS_TAG) {
364             return nullptr;
365         }
366     } else {
367         if (buttonRowNode->GetTag() != V2::FLEX_ETS_TAG) {
368             return nullptr;
369         }
370     }
371     if (buttonRowNode->GetChildren().empty()) {
372         return nullptr;
373     }
374     return buttonRowNode;
375 }
376 
PopBubble(bool tips)377 void BubblePattern::PopBubble(bool tips)
378 {
379     auto host = GetHost();
380     CHECK_NULL_VOID(host);
381     auto pipelineNg = host->GetContextRefPtr();
382     CHECK_NULL_VOID(pipelineNg);
383     auto overlayManager = pipelineNg->GetOverlayManager();
384     auto instanceId = pipelineNg->GetInstanceId();
385     CHECK_NULL_VOID(overlayManager);
386     auto popupInfo = overlayManager->GetPopupInfo(targetNodeId_);
387     if (!popupInfo.isCurrentOnShow || (tips && !popupInfo.isTips)) {
388         return;
389     }
390     popupInfo.markNeedUpdate = true;
391     CHECK_NULL_VOID(host);
392     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
393     CHECK_NULL_VOID(layoutProp);
394     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
395     auto isTips = layoutProp->GetIsTips().value_or(false);
396     if (showInSubWindow) {
397         if (isTips) {
398             SubwindowManager::GetInstance()->HideTipsNG(targetNodeId_, 0, instanceId);
399         } else {
400             SubwindowManager::GetInstance()->HidePopupNG(targetNodeId_, instanceId);
401         }
402     } else {
403         if (isTips) {
404             overlayManager->HideTips(targetNodeId_, popupInfo, 0);
405         } else {
406             overlayManager->HidePopup(targetNodeId_, popupInfo);
407         }
408     }
409 }
410 
GetPopupTheme()411 RefPtr<PopupTheme> BubblePattern::GetPopupTheme()
412 {
413     auto host = GetHost();
414     CHECK_NULL_RETURN(host, nullptr);
415     auto pipelineContext = host->GetContext();
416     CHECK_NULL_RETURN(pipelineContext, nullptr);
417     auto popupTheme = pipelineContext->GetTheme<PopupTheme>();
418     CHECK_NULL_RETURN(popupTheme, nullptr);
419     return popupTheme;
420 }
421 
Animation(RefPtr<RenderContext> & renderContext,const Color & endColor,int32_t duration,const RefPtr<Curve> & curve)422 void BubblePattern::Animation(
423     RefPtr<RenderContext>& renderContext, const Color& endColor, int32_t duration, const RefPtr<Curve>& curve)
424 {
425     auto host = GetHost();
426     CHECK_NULL_VOID(host);
427     AnimationOption option = AnimationOption();
428     option.SetCurve(curve);
429     option.SetDuration(duration);
430     option.SetFillMode(FillMode::FORWARDS);
431     AnimationUtils::Animate(
432         option, [buttonContext = renderContext, color = endColor]() { buttonContext->UpdateBackgroundColor(color); },
433         nullptr, nullptr, host->GetContextRefPtr());
434 }
435 
PostTask(const TaskExecutor::Task & task,const std::string & name)436 bool BubblePattern::PostTask(const TaskExecutor::Task& task, const std::string& name)
437 {
438     auto host = GetHost();
439     CHECK_NULL_RETURN(host, false);
440     auto pipeline = host->GetContext();
441     CHECK_NULL_RETURN(pipeline, false);
442     auto taskExecutor = pipeline->GetTaskExecutor();
443     CHECK_NULL_RETURN(taskExecutor, false);
444     return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name);
445 }
446 
StartEnteringTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)447 void BubblePattern::StartEnteringTransitionEffects(
448     const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
449 {
450     auto popupId = popupNode->GetId();
451     auto pattern = popupNode->GetPattern<BubblePattern>();
452     pattern->transitionStatus_ = TransitionStatus::ENTERING;
453     auto layoutProp = popupNode->GetLayoutProperty<BubbleLayoutProperty>();
454     CHECK_NULL_VOID(layoutProp);
455     layoutProp->UpdateVisibility(VisibleType::VISIBLE, false);
456     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
457     auto isBlock = layoutProp->GetBlockEventValue(true);
458     auto& renderContext = popupNode->GetRenderContext();
459     auto isTips = layoutProp->GetIsTips().value_or(false);
460     renderContext->SetTransitionInCallback(
461         [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock, isTips]() {
462             auto pattern = weak.Upgrade();
463             CHECK_NULL_VOID(pattern);
464             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
465                 return;
466             }
467             pattern->transitionStatus_ = TransitionStatus::NORMAL;
468             if (showInSubWindow && !isTips) {
469                 std::vector<Rect> rects;
470                 if (!isBlock) {
471                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
472                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
473                     rects.emplace_back(rect);
474                 } else {
475                     auto parentWindowRect = pattern->GetHostWindowRect();
476                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
477                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
478                     rects.emplace_back(parentWindowRect);
479                     rects.emplace_back(rect);
480                 }
481                 auto subWindowMgr = SubwindowManager::GetInstance();
482                 subWindowMgr->SetHotAreas(rects, SubwindowType::TYPE_POPUP, popupId, pattern->GetContainerId());
483             }
484             if (finish) {
485                 finish();
486             }
487         });
488 }
489 
StartExitingTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)490 void BubblePattern::StartExitingTransitionEffects(
491     const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
492 {
493     auto pattern = popupNode->GetPattern<BubblePattern>();
494     pattern->transitionStatus_ = TransitionStatus::EXITING;
495     auto layoutProperty = popupNode->GetLayoutProperty();
496     layoutProperty->UpdateVisibility(VisibleType::INVISIBLE, true);
497     auto renderContext = popupNode->GetRenderContext();
498     renderContext->SetTransitionOutCallback(
499         [weak = WeakClaim(this), finish]() {
500             auto pattern = weak.Upgrade();
501             CHECK_NULL_VOID(pattern);
502             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
503                 return;
504             }
505             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
506             if (finish) {
507                 finish();
508             }
509         });
510 }
511 
StartEnteringAnimation(std::function<void ()> finish)512 void BubblePattern::StartEnteringAnimation(std::function<void()> finish)
513 {
514     if (!arrowPlacement_.has_value()) {
515         delayShow_ = true;
516         finish_ = finish;
517         return;
518     }
519     if (IsOnShow()) {
520         return;
521     }
522 
523     if (transitionStatus_ == TransitionStatus::INVISIABLE) {
524         ResetToInvisible();
525     }
526 
527     StartOffsetEnteringAnimation();
528     if (finish) {
529         StartAlphaEnteringAnimation(finish);
530     } else {
531         StartAlphaEnteringAnimation(finish_);
532     }
533 }
534 
StartOffsetEnteringAnimation()535 void BubblePattern::StartOffsetEnteringAnimation()
536 {
537     auto host = GetHost();
538     CHECK_NULL_VOID(host);
539     AnimationOption optionPosition;
540     optionPosition.SetDuration(ENTRY_ANIMATION_DURATION);
541     optionPosition.SetCurve(Curves::FRICTION);
542     AnimationUtils::Animate(
543         optionPosition,
544         [weak = WeakClaim(this)]() {
545             auto pattern = weak.Upgrade();
546             CHECK_NULL_VOID(pattern);
547             auto renderContext = pattern->GetRenderContext();
548             CHECK_NULL_VOID(renderContext);
549             renderContext->UpdateOffset(OffsetT<Dimension>());
550             renderContext->SyncGeometryProperties(nullptr);
551         },
552         nullptr, nullptr, host->GetContextRefPtr());
553 }
554 
StartAlphaEnteringAnimation(std::function<void ()> finish)555 void BubblePattern::StartAlphaEnteringAnimation(std::function<void()> finish)
556 {
557     AnimationOption optionAlpha;
558     optionAlpha.SetDuration(ENTRY_ANIMATION_DURATION);
559     optionAlpha.SetCurve(Curves::SHARP);
560     auto host = GetHost();
561     CHECK_NULL_VOID(host);
562     auto popupId = host->GetId();
563     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
564     CHECK_NULL_VOID(layoutProp);
565     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
566     auto isBlock = layoutProp->GetBlockEventValue(true);
567     auto isTips = layoutProp->GetIsTips().value_or(false);
568     AnimationUtils::Animate(
569         optionAlpha,
570         [weak = WeakClaim(this)]() {
571             auto pattern = weak.Upgrade();
572             CHECK_NULL_VOID(pattern);
573             pattern->transitionStatus_ = TransitionStatus::ENTERING;
574             auto renderContext = pattern->GetRenderContext();
575             CHECK_NULL_VOID(renderContext);
576             renderContext->UpdateOpacity(VISIABLE_ALPHA);
577         },
578         [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock, isTips]() {
579             auto pattern = weak.Upgrade();
580             CHECK_NULL_VOID(pattern);
581             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
582                 return;
583             }
584             pattern->transitionStatus_ = TransitionStatus::NORMAL;
585             if (showInSubWindow && !isTips) {
586                 std::vector<Rect> rects;
587                 if (!isBlock) {
588                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
589                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
590                     rects.emplace_back(rect);
591                 } else {
592                     auto parentWindowRect = pattern->GetHostWindowRect();
593                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
594                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
595                     rects.emplace_back(parentWindowRect);
596                     rects.emplace_back(rect);
597                 }
598                 auto subWindowMgr = SubwindowManager::GetInstance();
599                 subWindowMgr->SetHotAreas(rects, SubwindowType::TYPE_POPUP, popupId, pattern->GetContainerId());
600             }
601             if (finish) {
602                 finish();
603             }
604         }, nullptr, host->GetContextRefPtr());
605 }
606 
StartExitingAnimation(std::function<void ()> finish)607 void BubblePattern::StartExitingAnimation(std::function<void()> finish)
608 {
609     StartOffsetExitingAnimation();
610     StartAlphaExitingAnimation(finish);
611 }
612 
StartOffsetExitingAnimation()613 void BubblePattern::StartOffsetExitingAnimation()
614 {
615     auto host = GetHost();
616     CHECK_NULL_VOID(host);
617     AnimationOption optionPosition;
618     optionPosition.SetDuration(EXIT_ANIMATION_DURATION);
619     optionPosition.SetCurve(Curves::FRICTION);
620     AnimationUtils::Animate(
621         optionPosition,
622         [weak = WeakClaim(this)]() {
623             auto pattern = weak.Upgrade();
624             CHECK_NULL_VOID(pattern);
625             auto renderContext = pattern->GetRenderContext();
626             CHECK_NULL_VOID(renderContext);
627             renderContext->UpdateOffset(pattern->GetInvisibleOffset());
628             renderContext->SyncGeometryProperties(nullptr);
629         },
630         nullptr, nullptr, host->GetContextRefPtr());
631 }
632 
StartAlphaExitingAnimation(std::function<void ()> finish)633 void BubblePattern::StartAlphaExitingAnimation(std::function<void()> finish)
634 {
635     auto host = GetHost();
636     CHECK_NULL_VOID(host);
637     AnimationOption optionAlpha;
638     optionAlpha.SetDuration(EXIT_ANIMATION_DURATION);
639     optionAlpha.SetCurve(Curves::SHARP);
640     AnimationUtils::Animate(
641         optionAlpha,
642         [weak = WeakClaim(this)]() {
643             auto pattern = weak.Upgrade();
644             CHECK_NULL_VOID(pattern);
645             pattern->transitionStatus_ = TransitionStatus::EXITING;
646             auto renderContext = pattern->GetRenderContext();
647             CHECK_NULL_VOID(renderContext);
648             renderContext->UpdateOpacity(INVISIABLE_ALPHA);
649         },
650         [weak = WeakClaim(this), finish]() {
651             auto pattern = weak.Upgrade();
652             CHECK_NULL_VOID(pattern);
653             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
654                 return;
655             }
656             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
657             if (finish) {
658                 finish();
659             }
660         }, nullptr, host->GetContextRefPtr());
661 }
662 
IsOnShow()663 bool BubblePattern::IsOnShow()
664 {
665     return (transitionStatus_ == TransitionStatus::ENTERING) || (transitionStatus_ == TransitionStatus::NORMAL);
666 }
667 
IsExiting()668 bool BubblePattern::IsExiting()
669 {
670     return transitionStatus_ == TransitionStatus::EXITING;
671 }
672 
GetInvisibleOffset()673 OffsetT<Dimension> BubblePattern::GetInvisibleOffset()
674 {
675     if (!arrowPlacement_.has_value()) {
676         return OffsetT<Dimension>();
677     }
678 
679     OffsetT<Dimension> offset;
680     switch (arrowPlacement_.value()) {
681         case Placement::LEFT:
682         case Placement::LEFT_TOP:
683         case Placement::LEFT_BOTTOM:
684             offset.AddX(INVISIABLE_OFFSET);
685             break;
686         case Placement::RIGHT:
687         case Placement::RIGHT_TOP:
688         case Placement::RIGHT_BOTTOM:
689             offset.AddX(INVISIABLE_OFFSET * -1);
690             break;
691         case Placement::TOP:
692         case Placement::TOP_LEFT:
693         case Placement::TOP_RIGHT:
694             offset.AddY(INVISIABLE_OFFSET);
695             break;
696         case Placement::BOTTOM:
697         case Placement::BOTTOM_LEFT:
698         case Placement::BOTTOM_RIGHT:
699             offset.AddY(INVISIABLE_OFFSET * -1);
700             break;
701         default:
702             break;
703     }
704     return offset;
705 }
706 
GetRenderContext()707 RefPtr<RenderContext> BubblePattern::GetRenderContext()
708 {
709     auto frameNode = GetHost();
710     CHECK_NULL_RETURN(frameNode, nullptr);
711     return frameNode->GetRenderContext();
712 }
713 
ResetToInvisible()714 void BubblePattern::ResetToInvisible()
715 {
716     auto renderContext = GetRenderContext();
717     CHECK_NULL_VOID(renderContext);
718 
719     renderContext->UpdateOpacity(INVISIABLE_ALPHA);
720     renderContext->UpdateOffset(GetInvisibleOffset());
721     renderContext->SyncGeometryProperties(nullptr);
722 }
723 
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)724 void BubblePattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
725 {
726     TAG_LOGI(AceLogTag::ACE_OVERLAY, "Popup OnWindowSizeChanged, reason: %{public}d", type);
727     if (type == WindowSizeChangeReason::MAXIMIZE || type == WindowSizeChangeReason::RECOVER ||
728         type == WindowSizeChangeReason::ROTATION || type == WindowSizeChangeReason::HIDE ||
729         type == WindowSizeChangeReason::TRANSFORM || type == WindowSizeChangeReason::CUSTOM_ANIMATION) {
730         auto host = GetHost();
731         CHECK_NULL_VOID(host);
732         auto pipelineNg = host->GetContextRefPtr();
733         CHECK_NULL_VOID(pipelineNg);
734         auto overlayManager = pipelineNg->GetOverlayManager();
735         CHECK_NULL_VOID(overlayManager);
736         overlayManager->HideAllPopups();
737         auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
738         CHECK_NULL_VOID(layoutProp);
739         auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
740         if (showInSubWindow) {
741             auto subwindow = SubwindowManager::GetInstance()->GetSubwindowByType(
742                 pipelineNg->GetInstanceId(), SubwindowType::TYPE_POPUP);
743             CHECK_NULL_VOID(subwindow);
744             subwindow->HidePopupNG(targetNodeId_);
745         }
746     }
747 }
748 
OnWindowHide()749 void BubblePattern::OnWindowHide()
750 {
751     TAG_LOGI(AceLogTag::ACE_OVERLAY, "Popup OnWindowHide start");
752     auto host = GetHost();
753     CHECK_NULL_VOID(host);
754     auto pipelineNg = host->GetContextRefPtr();
755     CHECK_NULL_VOID(pipelineNg);
756     auto overlayManager = pipelineNg->GetOverlayManager();
757     CHECK_NULL_VOID(overlayManager);
758     overlayManager->HideAllPopups();
759     CHECK_NULL_VOID(host);
760     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
761     CHECK_NULL_VOID(layoutProp);
762     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
763     if (showInSubWindow) {
764         auto subwindow = SubwindowManager::GetInstance()->GetSubwindowByType(
765             pipelineNg->GetInstanceId(), SubwindowType::TYPE_POPUP);
766         CHECK_NULL_VOID(subwindow);
767         subwindow->HidePopupNG(targetNodeId_);
768     }
769 }
770 
771 
UpdateText(const RefPtr<UINode> & node,const RefPtr<PopupTheme> & popupTheme)772 void BubblePattern::UpdateText(const RefPtr<UINode>& node, const RefPtr<PopupTheme>& popupTheme)
773 {
774     if (node->GetTag() == V2::TEXT_ETS_TAG) {
775         auto textNode = DynamicCast<FrameNode>(node);
776         CHECK_NULL_VOID(textNode);
777         auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
778         CHECK_NULL_VOID(textLayoutProperty);
779         auto parentNode = node->GetParent();
780         if (parentNode && parentNode->GetTag() == V2::BUTTON_ETS_TAG &&
781             !(Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
782             if (popupTheme->GetPopupDoubleButtonIsSameStyle()) {
783                 textLayoutProperty->UpdateTextColor(popupTheme->GetButtonFontColor());
784             }
785         } else if (!isSetMessageColor_) {
786             if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
787                 textLayoutProperty->UpdateTextColor(popupTheme->GetFontColor());
788             } else {
789                 textLayoutProperty->UpdateTextColor(popupTheme->GetFontPrimaryColor());
790             }
791         }
792         textNode->MarkModifyDone();
793         textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
794     } else {
795         for (const auto& childNode : node->GetChildren()) {
796             UpdateText(childNode, popupTheme);
797         }
798     }
799 }
800 
DumpInfo()801 void BubblePattern::DumpInfo()
802 {
803     DumpLog::GetInstance().AddDesc("enableArrow: " + std::to_string(dumpInfo_.enableArrow));
804     DumpLog::GetInstance().AddDesc("mask: " + std::to_string(dumpInfo_.mask));
805     DumpLog::GetInstance().AddDesc("targetTag: " + dumpInfo_.targetNode + ", targetID: "
806         + std::to_string(dumpInfo_.targetID));
807     DumpLog::GetInstance().AddDesc("targetOffset: " + dumpInfo_.targetOffset.ToString());
808     DumpLog::GetInstance().AddDesc("targetSize: " + dumpInfo_.targetSize.ToString());
809     DumpLog::GetInstance().AddDesc("touchRegion: " + dumpInfo_.touchRegion.ToString());
810     DumpLog::GetInstance().AddDesc("avoid top: " + std::to_string(dumpInfo_.top)
811         + ", bottom: " + std::to_string(dumpInfo_.bottom));
812     DumpLog::GetInstance().AddDesc("userOffset: " + dumpInfo_.userOffset.ToString());
813     DumpLog::GetInstance().AddDesc("targetSpace: " + dumpInfo_.targetSpace.ToString());
814     DumpLog::GetInstance().AddDesc("originPlacement: " + dumpInfo_.originPlacement);
815     DumpLog::GetInstance().AddDesc("finalPlacement: " + dumpInfo_.finalPlacement);
816     DumpLog::GetInstance().AddDesc("enableHoverMode: " + std::to_string(dumpInfo_.enableHoverMode));
817     DumpLog::GetInstance().AddDesc("avoidKeyboard: " + std::to_string(dumpInfo_.avoidKeyboard));
818 }
819 
UpdateBubbleText()820 void BubblePattern::UpdateBubbleText()
821 {
822     auto host = GetHost();
823     CHECK_NULL_VOID(host);
824     host->SetNeedCallChildrenUpdate(false);
825     auto context = host->GetContext();
826     CHECK_NULL_VOID(context);
827     auto popupTheme = context->GetTheme<PopupTheme>();
828     CHECK_NULL_VOID(popupTheme);
829     UpdateText(host, popupTheme);
830     host->MarkDirtyNode();
831 }
832 
UpdateStyleOption(BlurStyle blurStyle,bool needUpdateShadow)833 void BubblePattern::UpdateStyleOption(BlurStyle blurStyle, bool needUpdateShadow)
834 {
835     auto host = GetHost();
836     CHECK_NULL_VOID(host);
837     auto popupTheme = GetPopupTheme();
838     CHECK_NULL_VOID(popupTheme);
839     auto childNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
840     CHECK_NULL_VOID(childNode);
841     auto popupPaintProp = host->GetPaintProperty<BubbleRenderProperty>();
842     CHECK_NULL_VOID(popupPaintProp);
843     auto renderContext = childNode->GetRenderContext();
844     CHECK_NULL_VOID(renderContext);
845     auto defaultBGcolor = popupTheme->GetDefaultBGColor();
846     auto backgroundColor = popupPaintProp->GetBackgroundColor().value_or(defaultBGcolor);
847     renderContext->UpdateBackgroundColor(backgroundColor);
848     BlurStyleOption styleOption;
849     styleOption.blurStyle = blurStyle;
850     styleOption.colorMode = static_cast<ThemeColorMode>(popupTheme->GetBgThemeColorMode());
851     renderContext->UpdateBackBlurStyle(styleOption);
852     if (needUpdateShadow) {
853         auto shadow = Shadow::CreateShadow(ShadowStyle::OuterDefaultSM);
854         renderContext->UpdateBackShadow(shadow);
855     }
856 }
857 
OnColorConfigurationUpdate()858 void BubblePattern::OnColorConfigurationUpdate()
859 {
860     // Tips: Color mode changes are already adapted, so ConfigChangePerform() control is not required.
861     if (isTips_) {
862         UpdateStyleOption(BlurStyle::COMPONENT_REGULAR, true);
863     } else if (SystemProperties::ConfigChangePerform()) {
864         UpdateStyleOption(popupParam_->GetBlurStyle(), false);
865     }
866     if (isCustomPopup_) {
867         return;
868     }
869     auto context = GetContext();
870     CHECK_NULL_VOID(context);
871     colorMode_ = context->GetColorMode();
872     UpdateBubbleText();
873 }
874 
UpdateAgingTextSize()875 void BubblePattern::UpdateAgingTextSize()
876 {
877     if (isCustomPopup_) {
878         return;
879     }
880     CHECK_NULL_VOID(messageNode_);
881     messageNode_->MarkDirtyNode();
882 }
883 
UpdateBubbleText(const Color & value)884 void BubblePattern::UpdateBubbleText(const Color& value)
885 {
886     auto messagenode = GetMessageNode();
887     CHECK_NULL_VOID(messagenode);
888     auto textLayoutProps = messagenode->GetLayoutProperty<TextLayoutProperty>();
889     CHECK_NULL_VOID(textLayoutProps);
890     textLayoutProps->UpdateTextColor(value);
891     messagenode->MarkModifyDone();
892     messagenode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
893 }
894 
UpdateBubbleBackGroundColor(const Color & value)895 void BubblePattern::UpdateBubbleBackGroundColor(const Color& value)
896 {
897     auto host = GetHost();
898     CHECK_NULL_VOID(host);
899     auto popupPaintProp = host->GetPaintProperty<BubbleRenderProperty>();
900     CHECK_NULL_VOID(popupPaintProp);
901     popupPaintProp->UpdateBackgroundColor(value);
902     CHECK_NULL_VOID(popupParam_);
903     UpdateStyleOption(popupParam_->GetBlurStyle(), false);
904     host->MarkModifyDone();
905     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
906 }
907 
UpdateMaskColor(const Color & value)908 void BubblePattern::UpdateMaskColor(const Color& value)
909 {
910     auto host = GetHost();
911     CHECK_NULL_VOID(host);
912     auto popupPaintProp = host->GetPaintProperty<BubbleRenderProperty>();
913     CHECK_NULL_VOID(popupPaintProp);
914     popupPaintProp->UpdateMaskColor(value);
915     host->MarkModifyDone();
916     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
917 }
918 
UpdateMask(bool maskValue)919 void BubblePattern::UpdateMask(bool maskValue)
920 {
921     auto host = GetHost();
922     CHECK_NULL_VOID(host);
923     auto popupPaintProp = host->GetPaintProperty<BubbleLayoutProperty>();
924     CHECK_NULL_VOID(popupPaintProp);
925     popupPaintProp->UpdateBlockEvent(maskValue);
926     host->MarkModifyDone();
927     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
928 }
929 
UpdateArrowWidth(const CalcDimension & dimension)930 void BubblePattern::UpdateArrowWidth(const CalcDimension& dimension)
931 {
932     auto host = GetHost();
933     CHECK_NULL_VOID(host);
934     auto popupLayoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
935     CHECK_NULL_VOID(popupLayoutProp);
936     if (dimension.Value() > 0 && dimension.Unit() != DimensionUnit::PERCENT) {
937         popupLayoutProp->UpdateArrowWidth(dimension);
938     }
939 
940     host->MarkModifyDone();
941     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
942 }
943 
UpdateArrowHeight(const CalcDimension & dimension)944 void BubblePattern::UpdateArrowHeight(const CalcDimension& dimension)
945 {
946     auto host = GetHost();
947     CHECK_NULL_VOID(host);
948     auto popupLayoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
949     CHECK_NULL_VOID(popupLayoutProp);
950     if (dimension.Value() > 0 && dimension.Unit() != DimensionUnit::PERCENT) {
951         popupLayoutProp->UpdateArrowHeight(dimension);
952     }
953     host->MarkModifyDone();
954     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
955 }
956 
UpdateWidth(const CalcDimension & dimension)957 void BubblePattern::UpdateWidth(const CalcDimension& dimension)
958 {
959     auto host = GetHost();
960     CHECK_NULL_VOID(host);
961     auto childNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
962     CHECK_NULL_VOID(childNode);
963     auto childLayoutProperty = childNode->GetLayoutProperty();
964     CHECK_NULL_VOID(childLayoutProperty);
965     if (dimension.Value() > 0) {
966         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dimension), std::nullopt));
967     }
968     host->MarkModifyDone();
969     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
970 }
971 
UpdateRadius(const CalcDimension & dimension)972 void BubblePattern::UpdateRadius(const CalcDimension& dimension)
973 {
974     auto host = GetHost();
975     CHECK_NULL_VOID(host);
976     auto layoutProps = host->GetLayoutProperty<BubbleLayoutProperty>();
977     if (dimension.Value() >= 0) {
978         layoutProps->UpdateRadius(dimension);
979     }
980     host->MarkModifyDone();
981     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
982 }
983 
984 
985 } // namespace OHOS::Ace::NG
986