• 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/memory/ace_type.h"
18 #include "base/subwindow/subwindow.h"
19 #include "base/subwindow/subwindow_manager.h"
20 #include "base/utils/utils.h"
21 #include "core/common/container.h"
22 #include "base/log/dump_log.h"
23 #include "core/common/container_scope.h"
24 #include "core/common/window_animation_config.h"
25 #include "core/components/common/properties/shadow_config.h"
26 #include "core/components/container_modal/container_modal_constants.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/base/ui_node.h"
29 #include "core/components_ng/pattern/bubble/bubble_layout_property.h"
30 #include "core/components_ng/pattern/bubble/bubble_render_property.h"
31 #include "core/components_ng/pattern/text/text_layout_property.h"
32 #include "core/components_ng/property/property.h"
33 #include "core/components_v2/inspector/inspector_constants.h"
34 #include "core/event/touch_event.h"
35 #include "core/pipeline/pipeline_base.h"
36 #include "core/pipeline/pipeline_context.h"
37 #include "core/pipeline_ng/pipeline_context.h"
38 
39 namespace OHOS::Ace::NG {
40 namespace {
41 constexpr float VISIABLE_ALPHA = 1.0f;
42 constexpr float INVISIABLE_ALPHA = 0.0f;
43 constexpr int32_t ENTRY_ANIMATION_DURATION = 250;
44 constexpr int32_t EXIT_ANIMATION_DURATION = 100;
45 const Dimension INVISIABLE_OFFSET = 8.0_px;
46 } // namespace
47 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)48 bool BubblePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
49 {
50     if (skipMeasure && skipLayout) {
51         return false;
52     }
53     auto host = GetHost();
54     CHECK_NULL_RETURN(host, false);
55     auto paintProperty = host->GetPaintProperty<BubbleRenderProperty>();
56     CHECK_NULL_RETURN(paintProperty, false);
57     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
58     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
59     auto bubbleLayoutAlgorithm = DynamicCast<BubbleLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
60     CHECK_NULL_RETURN(bubbleLayoutAlgorithm, false);
61 
62     showArrow_ = bubbleLayoutAlgorithm->ShowArrow();
63     arrowPosition_ = bubbleLayoutAlgorithm->GetArrowPosition();
64     childOffset_ = bubbleLayoutAlgorithm->GetChildOffset();
65     childSize_ = bubbleLayoutAlgorithm->GetChildSize();
66     touchRegion_ = bubbleLayoutAlgorithm->GetTouchRegion();
67     hostWindowRect_ = bubbleLayoutAlgorithm->GetHostWindowRect();
68     targetOffset_ = bubbleLayoutAlgorithm->GetTargetOffset();
69     targetSize_ = bubbleLayoutAlgorithm->GetTargetSize();
70     arrowPlacement_ = bubbleLayoutAlgorithm->GetArrowPlacement();
71     clipPath_ = bubbleLayoutAlgorithm->GetClipPath();
72     clipFrameNode_ = bubbleLayoutAlgorithm->GetClipFrameNode();
73     arrowOffsetsFromClip_ = bubbleLayoutAlgorithm->GetArrowOffsetsFromClip();
74     arrowWidth_ = bubbleLayoutAlgorithm->GetArrowWidth();
75     arrowHeight_ = bubbleLayoutAlgorithm->GetArrowHeight();
76     border_ = bubbleLayoutAlgorithm->GetBorder();
77     dumpInfo_ = bubbleLayoutAlgorithm->GetDumpInfo();
78     paintProperty->UpdatePlacement(bubbleLayoutAlgorithm->GetArrowPlacement());
79     if (delayShow_) {
80         delayShow_ = false;
81         if (transitionStatus_ == TransitionStatus::INVISIABLE) {
82             StartEnteringAnimation(nullptr);
83         }
84     }
85     return true;
86 }
87 
OnModifyDone()88 void BubblePattern::OnModifyDone()
89 {
90     if (SystemProperties::GetColorMode() != colorMode_ && !isCustomPopup_) {
91         colorMode_ = SystemProperties::GetColorMode();
92         UpdateBubbleText();
93     }
94     UpdateAgingTextSize();
95     Pattern::OnModifyDone();
96     InitTouchEvent();
97     RegisterButtonOnHover();
98     RegisterButtonOnTouch();
99 }
100 
AddPipelineCallBack()101 void BubblePattern::AddPipelineCallBack()
102 {
103     auto host = GetHost();
104     CHECK_NULL_VOID(host);
105     auto pipelineContext = PipelineContext::GetCurrentContext();
106     CHECK_NULL_VOID(pipelineContext);
107     pipelineContext->AddWindowSizeChangeCallback(host->GetId());
108     pipelineContext->AddWindowStateChangedCallback(host->GetId());
109 }
110 
OnAttachToFrameNode()111 void BubblePattern::OnAttachToFrameNode()
112 {
113     auto host = GetHost();
114     CHECK_NULL_VOID(host);
115     host->GetRenderContext()->SetClipToFrame(true);
116 
117     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
118     CHECK_NULL_VOID(targetNode);
119     auto pipelineContext = host->GetContextRefPtr();
120     CHECK_NULL_VOID(pipelineContext);
121     hasOnAreaChange_ = pipelineContext->HasOnAreaChangeNode(targetNode->GetId());
122     auto eventHub = targetNode->GetEventHub<EventHub>();
123     CHECK_NULL_VOID(eventHub);
124     OnAreaChangedFunc onAreaChangedFunc = [popupNodeWk = WeakPtr<FrameNode>(host)](const RectF& /* oldRect */,
125                                               const OffsetF& /* oldOrigin */, const RectF& /* rect */,
126                                               const OffsetF& /* origin */) {
127         auto popupNode = popupNodeWk.Upgrade();
128         CHECK_NULL_VOID(popupNode);
129         popupNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
130     };
131     eventHub->AddInnerOnAreaChangedCallback(host->GetId(), std::move(onAreaChangedFunc));
132 }
133 
OnDetachFromFrameNode(FrameNode * frameNode)134 void BubblePattern::OnDetachFromFrameNode(FrameNode* frameNode)
135 {
136     auto pipeline = PipelineContext::GetCurrentContext();
137     CHECK_NULL_VOID(pipeline);
138     pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
139     pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
140     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
141     CHECK_NULL_VOID(targetNode);
142     if (!hasOnAreaChange_) {
143         pipeline->RemoveOnAreaChangeNode(targetNode->GetId());
144     }
145 }
146 
InitTouchEvent()147 void BubblePattern::InitTouchEvent()
148 {
149     auto host = GetHost();
150     CHECK_NULL_VOID(host);
151     auto hub = host->GetEventHub<EventHub>();
152     CHECK_NULL_VOID(hub);
153     auto gestureHub = hub->GetOrCreateGestureEventHub();
154     CHECK_NULL_VOID(gestureHub);
155     if (touchEvent_) {
156         return;
157     }
158     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
159         auto pattern = weak.Upgrade();
160         if (pattern) {
161             pattern->HandleTouchEvent(info);
162         }
163     };
164     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
165     gestureHub->AddTouchEvent(touchEvent_);
166 }
167 
HandleTouchEvent(const TouchEventInfo & info)168 void BubblePattern::HandleTouchEvent(const TouchEventInfo& info)
169 {
170     if (info.GetTouches().empty()) {
171         return;
172     }
173     auto touchType = info.GetTouches().front().GetTouchType();
174     auto clickPos = info.GetTouches().front().GetLocalLocation();
175     if (touchType == TouchType::DOWN) {
176         HandleTouchDown(clickPos);
177     }
178 }
179 
HandleTouchDown(const Offset & clickPosition)180 void BubblePattern::HandleTouchDown(const Offset& clickPosition)
181 {
182     auto host = GetHost();
183     CHECK_NULL_VOID(host);
184     auto bubbleRenderProp = host->GetPaintProperty<BubbleRenderProperty>();
185     CHECK_NULL_VOID(bubbleRenderProp);
186     if (touchRegion_.IsInRegion(PointF(clickPosition.GetX(), clickPosition.GetY()))) {
187         return;
188     }
189     auto autoCancel = bubbleRenderProp->GetAutoCancel().value_or(true);
190     if (autoCancel) {
191         TAG_LOGD(AceLogTag::ACE_DIALOG, "handle popup touch down event");
192         if (!GetInteractiveDismiss()) {
193             return;
194         }
195         if (HasOnWillDismiss()) {
196             auto pipelineNg = PipelineContext::GetCurrentContext();
197             CHECK_NULL_VOID(pipelineNg);
198             auto overlayManager = pipelineNg->GetOverlayManager();
199             CHECK_NULL_VOID(overlayManager);
200             overlayManager->SetDismissPopupId(targetNodeId_);
201             CallOnWillDismiss(static_cast<int32_t>(DismissReason::TOUCH_OUTSIDE));
202             return;
203         }
204         PopBubble();
205     }
206 }
207 
RegisterButtonOnHover()208 void BubblePattern::RegisterButtonOnHover()
209 {
210     if (mouseEventInitFlag_) {
211         return;
212     }
213     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
214     CHECK_NULL_VOID(paintProps);
215     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
216     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
217     auto custom = paintProps->GetUseCustom().value_or(false);
218     if (custom) {
219         return;
220     }
221     if (!primaryButtonShow && !secondaryButtonShow) {
222         return;
223     }
224     auto buttonRowNode = GetButtonRowNode();
225     for (const auto& child : buttonRowNode->GetChildren()) {
226         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
227         CHECK_NULL_VOID(buttonNode);
228         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
229             return;
230         }
231         auto inputHub = buttonNode->GetOrCreateInputEventHub();
232         CHECK_NULL_VOID(inputHub);
233         auto mouseTask = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)](bool isHover) {
234             auto pattern = weak.Upgrade();
235             CHECK_NULL_VOID(pattern);
236             auto buttonNode = buttonNodeWK.Upgrade();
237             CHECK_NULL_VOID(buttonNode);
238             pattern->ButtonOnHover(isHover, buttonNode);
239         };
240         auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
241         inputHub->AddOnHoverEvent(mouseEvent);
242     }
243     mouseEventInitFlag_ = true;
244 }
245 
ButtonOnHover(bool isHover,const RefPtr<NG::FrameNode> & buttonNode)246 void BubblePattern::ButtonOnHover(bool isHover, const RefPtr<NG::FrameNode>& buttonNode)
247 {
248     auto renderContext = buttonNode->GetRenderContext();
249     CHECK_NULL_VOID(renderContext);
250     auto pipeline = PipelineBase::GetCurrentContext();
251     CHECK_NULL_VOID(pipeline);
252     auto theme = pipeline->GetTheme<PopupTheme>();
253     isHover_ = isHover;
254     auto hoverColor = theme->GetButtonHoverColor();
255     auto backgroundColor = theme->GetButtonBackgroundColor();
256     if (isHover) {
257         // normal to hover
258         Animation(renderContext, hoverColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
259     } else {
260         // hover to normal
261         Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
262     }
263 }
264 
RegisterButtonOnTouch()265 void BubblePattern::RegisterButtonOnTouch()
266 {
267     if (touchEventInitFlag_) {
268         return;
269     }
270     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
271     CHECK_NULL_VOID(paintProps);
272     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
273     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
274     auto custom = paintProps->GetUseCustom().value_or(false);
275     if (custom) {
276         return;
277     }
278     if (!primaryButtonShow && !secondaryButtonShow) {
279         return;
280     }
281 
282     auto buttonRowNode = GetButtonRowNode();
283     for (const auto& child : buttonRowNode->GetChildren()) {
284         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
285         CHECK_NULL_VOID(buttonNode);
286         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
287             return;
288         }
289         auto gestureHub = buttonNode->GetOrCreateGestureEventHub();
290         CHECK_NULL_VOID(gestureHub);
291         auto touchCallback = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)]
292             (const TouchEventInfo& info) {
293             auto pattern = weak.Upgrade();
294             CHECK_NULL_VOID(pattern);
295             auto buttonNode = buttonNodeWK.Upgrade();
296             CHECK_NULL_VOID(buttonNode);
297             pattern->ButtonOnPress(info, buttonNode);
298         };
299         auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
300         gestureHub->AddTouchEvent(touchEvent);
301     }
302     touchEventInitFlag_ = true;
303 }
304 
ButtonOnPress(const TouchEventInfo & info,const RefPtr<NG::FrameNode> & buttonNode)305 void BubblePattern::ButtonOnPress(const TouchEventInfo& info, const RefPtr<NG::FrameNode>& buttonNode)
306 {
307     auto touchType = info.GetTouches().front().GetTouchType();
308     auto renderContext = buttonNode->GetRenderContext();
309     CHECK_NULL_VOID(renderContext);
310     auto pipeline = PipelineBase::GetCurrentContext();
311     CHECK_NULL_VOID(pipeline);
312     auto theme = pipeline->GetTheme<PopupTheme>();
313     CHECK_NULL_VOID(theme);
314     auto pressColor = theme->GetButtonPressColor();
315     auto hoverColor = theme->GetButtonHoverColor();
316     auto backgroundColor = theme->GetButtonBackgroundColor();
317     if (touchType == TouchType::DOWN) {
318         if (isHover_) {
319             // hover to press
320             Animation(renderContext, pressColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
321         } else {
322             // normal to press
323             Animation(renderContext, pressColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
324         }
325     } else if (touchType == TouchType::UP) {
326         if (isHover_) {
327             // press to hover
328             Animation(renderContext, hoverColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
329         } else {
330             // press to normal
331             Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
332         }
333     }
334 }
335 
GetButtonRowNode()336 RefPtr<FrameNode> BubblePattern::GetButtonRowNode()
337 {
338     auto host = GetHost();
339     CHECK_NULL_RETURN(host, nullptr);
340     auto columnNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
341     CHECK_NULL_RETURN(columnNode, nullptr);
342     auto lastColumnNode = AceType::DynamicCast<FrameNode>(columnNode->GetLastChild());
343     CHECK_NULL_RETURN(lastColumnNode, nullptr);
344     auto buttonRowNode = AceType::DynamicCast<FrameNode>(lastColumnNode->GetLastChild());
345     CHECK_NULL_RETURN(buttonRowNode, nullptr);
346     if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
347         if (buttonRowNode->GetTag() != V2::ROW_ETS_TAG) {
348             return nullptr;
349         }
350     } else {
351         if (buttonRowNode->GetTag() != V2::FLEX_ETS_TAG) {
352             return nullptr;
353         }
354     }
355     if (buttonRowNode->GetChildren().empty()) {
356         return nullptr;
357     }
358     return buttonRowNode;
359 }
360 
PopBubble()361 void BubblePattern::PopBubble()
362 {
363     auto pipelineNg = PipelineContext::GetCurrentContext();
364     CHECK_NULL_VOID(pipelineNg);
365     auto overlayManager = pipelineNg->GetOverlayManager();
366     CHECK_NULL_VOID(overlayManager);
367     auto popupInfo = overlayManager->GetPopupInfo(targetNodeId_);
368     if (!popupInfo.isCurrentOnShow) {
369         return;
370     }
371     popupInfo.markNeedUpdate = true;
372     auto host = GetHost();
373     CHECK_NULL_VOID(host);
374     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
375     CHECK_NULL_VOID(layoutProp);
376     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
377     if (showInSubWindow) {
378         SubwindowManager::GetInstance()->HidePopupNG(targetNodeId_);
379     } else {
380         overlayManager->HidePopup(targetNodeId_, popupInfo);
381     }
382 }
383 
GetPopupTheme()384 RefPtr<PopupTheme> BubblePattern::GetPopupTheme()
385 {
386     auto pipelineContext = PipelineBase::GetCurrentContext();
387     CHECK_NULL_RETURN(pipelineContext, nullptr);
388     auto popupTheme = pipelineContext->GetTheme<PopupTheme>();
389     CHECK_NULL_RETURN(popupTheme, nullptr);
390     return popupTheme;
391 }
392 
Animation(RefPtr<RenderContext> & renderContext,const Color & endColor,int32_t duration,const RefPtr<Curve> & curve)393 void BubblePattern::Animation(
394     RefPtr<RenderContext>& renderContext, const Color& endColor, int32_t duration, const RefPtr<Curve>& curve)
395 {
396     AnimationOption option = AnimationOption();
397     option.SetCurve(curve);
398     option.SetDuration(duration);
399     option.SetFillMode(FillMode::FORWARDS);
400     AnimationUtils::Animate(
401         option, [buttonContext = renderContext, color = endColor]() { buttonContext->UpdateBackgroundColor(color); });
402 }
403 
PostTask(const TaskExecutor::Task & task,const std::string & name)404 bool BubblePattern::PostTask(const TaskExecutor::Task& task, const std::string& name)
405 {
406     auto pipeline = PipelineBase::GetCurrentContext();
407     CHECK_NULL_RETURN(pipeline, false);
408     auto taskExecutor = pipeline->GetTaskExecutor();
409     CHECK_NULL_RETURN(taskExecutor, false);
410     return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name);
411 }
412 
StartEnteringTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)413 void BubblePattern::StartEnteringTransitionEffects(
414     const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
415 {
416     auto popupId = popupNode->GetId();
417     auto pattern = popupNode->GetPattern<BubblePattern>();
418     pattern->transitionStatus_ = TransitionStatus::ENTERING;
419     auto layoutProp = popupNode->GetLayoutProperty<BubbleLayoutProperty>();
420     CHECK_NULL_VOID(layoutProp);
421     layoutProp->UpdateVisibility(VisibleType::VISIBLE, false);
422     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
423     auto isBlock = layoutProp->GetBlockEventValue(true);
424     auto& renderContext = popupNode->GetRenderContext();
425     renderContext->SetTransitionInCallback(
426         [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock]() {
427             auto pattern = weak.Upgrade();
428             CHECK_NULL_VOID(pattern);
429             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
430                 return;
431             }
432             pattern->transitionStatus_ = TransitionStatus::NORMAL;
433             if (showInSubWindow) {
434                 std::vector<Rect> rects;
435                 if (!isBlock) {
436                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
437                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
438                     rects.emplace_back(rect);
439                 } else {
440                     auto parentWindowRect = pattern->GetHostWindowRect();
441                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
442                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
443                     rects.emplace_back(parentWindowRect);
444                     rects.emplace_back(rect);
445                 }
446                 auto subWindowMgr = SubwindowManager::GetInstance();
447                 subWindowMgr->SetHotAreas(rects, popupId, pattern->GetContainerId());
448             }
449             if (finish) {
450                 finish();
451             }
452         });
453 }
454 
StartExitingTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)455 void BubblePattern::StartExitingTransitionEffects(
456     const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
457 {
458     auto pattern = popupNode->GetPattern<BubblePattern>();
459     pattern->transitionStatus_ = TransitionStatus::EXITING;
460     auto layoutProperty = popupNode->GetLayoutProperty();
461     layoutProperty->UpdateVisibility(VisibleType::INVISIBLE, true);
462     auto renderContext = popupNode->GetRenderContext();
463     renderContext->SetTransitionOutCallback(
464         [weak = WeakClaim(this), finish]() {
465             auto pattern = weak.Upgrade();
466             CHECK_NULL_VOID(pattern);
467             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
468                 return;
469             }
470             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
471             if (finish) {
472                 finish();
473             }
474         });
475 }
476 
StartEnteringAnimation(std::function<void ()> finish)477 void BubblePattern::StartEnteringAnimation(std::function<void()> finish)
478 {
479     if (!arrowPlacement_.has_value()) {
480         delayShow_ = true;
481         finish_ = finish;
482         return;
483     }
484     if (IsOnShow()) {
485         return;
486     }
487 
488     if (transitionStatus_ == TransitionStatus::INVISIABLE) {
489         ResetToInvisible();
490     }
491 
492     StartOffsetEnteringAnimation();
493     if (finish) {
494         StartAlphaEnteringAnimation(finish);
495     } else {
496         StartAlphaEnteringAnimation(finish_);
497     }
498 }
499 
StartOffsetEnteringAnimation()500 void BubblePattern::StartOffsetEnteringAnimation()
501 {
502     AnimationOption optionPosition;
503     optionPosition.SetDuration(ENTRY_ANIMATION_DURATION);
504     optionPosition.SetCurve(Curves::FRICTION);
505     AnimationUtils::Animate(
506         optionPosition,
507         [weak = WeakClaim(this)]() {
508             auto pattern = weak.Upgrade();
509             CHECK_NULL_VOID(pattern);
510             auto renderContext = pattern->GetRenderContext();
511             CHECK_NULL_VOID(renderContext);
512             renderContext->UpdateOffset(OffsetT<Dimension>());
513             renderContext->SyncGeometryProperties(nullptr);
514         },
515         nullptr);
516 }
517 
StartAlphaEnteringAnimation(std::function<void ()> finish)518 void BubblePattern::StartAlphaEnteringAnimation(std::function<void()> finish)
519 {
520     AnimationOption optionAlpha;
521     optionAlpha.SetDuration(ENTRY_ANIMATION_DURATION);
522     optionAlpha.SetCurve(Curves::SHARP);
523     auto host = GetHost();
524     auto popupId = host->GetId();
525     CHECK_NULL_VOID(host);
526     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
527     CHECK_NULL_VOID(layoutProp);
528     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
529     auto isBlock = layoutProp->GetBlockEventValue(true);
530     AnimationUtils::Animate(
531         optionAlpha,
532         [weak = WeakClaim(this)]() {
533             auto pattern = weak.Upgrade();
534             CHECK_NULL_VOID(pattern);
535             pattern->transitionStatus_ = TransitionStatus::ENTERING;
536             auto renderContext = pattern->GetRenderContext();
537             CHECK_NULL_VOID(renderContext);
538             renderContext->UpdateOpacity(VISIABLE_ALPHA);
539         },
540         [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock]() {
541             auto pattern = weak.Upgrade();
542             CHECK_NULL_VOID(pattern);
543             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
544                 return;
545             }
546             pattern->transitionStatus_ = TransitionStatus::NORMAL;
547             if (showInSubWindow) {
548                 std::vector<Rect> rects;
549                 if (!isBlock) {
550                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
551                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
552                     rects.emplace_back(rect);
553                 } else {
554                     auto parentWindowRect = pattern->GetHostWindowRect();
555                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
556                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
557                     rects.emplace_back(parentWindowRect);
558                     rects.emplace_back(rect);
559                 }
560                 auto subWindowMgr = SubwindowManager::GetInstance();
561                 subWindowMgr->SetHotAreas(rects, popupId, pattern->GetContainerId());
562             }
563             if (finish) {
564                 finish();
565             }
566         });
567 }
568 
StartExitingAnimation(std::function<void ()> finish)569 void BubblePattern::StartExitingAnimation(std::function<void()> finish)
570 {
571     StartOffsetExitingAnimation();
572     StartAlphaExitingAnimation(finish);
573 }
574 
StartOffsetExitingAnimation()575 void BubblePattern::StartOffsetExitingAnimation()
576 {
577     AnimationOption optionPosition;
578     optionPosition.SetDuration(EXIT_ANIMATION_DURATION);
579     optionPosition.SetCurve(Curves::FRICTION);
580     AnimationUtils::Animate(
581         optionPosition,
582         [weak = WeakClaim(this)]() {
583             auto pattern = weak.Upgrade();
584             CHECK_NULL_VOID(pattern);
585             auto renderContext = pattern->GetRenderContext();
586             CHECK_NULL_VOID(renderContext);
587             renderContext->UpdateOffset(pattern->GetInvisibleOffset());
588             renderContext->SyncGeometryProperties(nullptr);
589         },
590         nullptr);
591 }
592 
StartAlphaExitingAnimation(std::function<void ()> finish)593 void BubblePattern::StartAlphaExitingAnimation(std::function<void()> finish)
594 {
595     AnimationOption optionAlpha;
596     optionAlpha.SetDuration(EXIT_ANIMATION_DURATION);
597     optionAlpha.SetCurve(Curves::SHARP);
598     AnimationUtils::Animate(
599         optionAlpha,
600         [weak = WeakClaim(this)]() {
601             auto pattern = weak.Upgrade();
602             CHECK_NULL_VOID(pattern);
603             pattern->transitionStatus_ = TransitionStatus::EXITING;
604             auto renderContext = pattern->GetRenderContext();
605             CHECK_NULL_VOID(renderContext);
606             renderContext->UpdateOpacity(INVISIABLE_ALPHA);
607         },
608         [weak = WeakClaim(this), finish]() {
609             auto pattern = weak.Upgrade();
610             CHECK_NULL_VOID(pattern);
611             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
612                 return;
613             }
614             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
615             if (finish) {
616                 finish();
617             }
618         });
619 }
620 
IsOnShow()621 bool BubblePattern::IsOnShow()
622 {
623     return (transitionStatus_ == TransitionStatus::ENTERING) || (transitionStatus_ == TransitionStatus::NORMAL);
624 }
625 
IsExiting()626 bool BubblePattern::IsExiting()
627 {
628     return transitionStatus_ == TransitionStatus::EXITING;
629 }
630 
GetInvisibleOffset()631 OffsetT<Dimension> BubblePattern::GetInvisibleOffset()
632 {
633     if (!arrowPlacement_.has_value()) {
634         return OffsetT<Dimension>();
635     }
636 
637     OffsetT<Dimension> offset;
638     switch (arrowPlacement_.value()) {
639         case Placement::LEFT:
640         case Placement::LEFT_TOP:
641         case Placement::LEFT_BOTTOM:
642             offset.AddX(INVISIABLE_OFFSET);
643             break;
644         case Placement::RIGHT:
645         case Placement::RIGHT_TOP:
646         case Placement::RIGHT_BOTTOM:
647             offset.AddX(INVISIABLE_OFFSET * -1);
648             break;
649         case Placement::TOP:
650         case Placement::TOP_LEFT:
651         case Placement::TOP_RIGHT:
652             offset.AddY(INVISIABLE_OFFSET);
653             break;
654         case Placement::BOTTOM:
655         case Placement::BOTTOM_LEFT:
656         case Placement::BOTTOM_RIGHT:
657             offset.AddY(INVISIABLE_OFFSET * -1);
658             break;
659         default:
660             break;
661     }
662     return offset;
663 }
664 
GetRenderContext()665 RefPtr<RenderContext> BubblePattern::GetRenderContext()
666 {
667     auto frameNode = GetHost();
668     CHECK_NULL_RETURN(frameNode, nullptr);
669     return frameNode->GetRenderContext();
670 }
671 
ResetToInvisible()672 void BubblePattern::ResetToInvisible()
673 {
674     auto renderContext = GetRenderContext();
675     CHECK_NULL_VOID(renderContext);
676 
677     renderContext->UpdateOpacity(INVISIABLE_ALPHA);
678     renderContext->UpdateOffset(GetInvisibleOffset());
679     renderContext->SyncGeometryProperties(nullptr);
680 }
681 
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)682 void BubblePattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
683 {
684     switch (type) {
685         case WindowSizeChangeReason::UNDEFINED:
686         case WindowSizeChangeReason::MOVE:
687         case WindowSizeChangeReason::RESIZE:
688         case WindowSizeChangeReason::DRAG_START:
689         case WindowSizeChangeReason::DRAG:
690         case WindowSizeChangeReason::DRAG_END: {
691             break;
692         }
693         default: {
694             auto pipelineNg = PipelineContext::GetCurrentContext();
695             CHECK_NULL_VOID(pipelineNg);
696             auto overlayManager = pipelineNg->GetOverlayManager();
697             CHECK_NULL_VOID(overlayManager);
698             overlayManager->HideAllPopups();
699             auto host = GetHost();
700             CHECK_NULL_VOID(host);
701             auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
702             CHECK_NULL_VOID(layoutProp);
703             auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
704             if (showInSubWindow) {
705                 auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(Container::CurrentId());
706                 CHECK_NULL_VOID(subwindow);
707                 subwindow->HidePopupNG(targetNodeId_);
708             }
709         }
710     }
711 }
712 
OnWindowHide()713 void BubblePattern::OnWindowHide()
714 {
715     auto pipelineNg = PipelineContext::GetCurrentContext();
716     CHECK_NULL_VOID(pipelineNg);
717     auto overlayManager = pipelineNg->GetOverlayManager();
718     CHECK_NULL_VOID(overlayManager);
719     overlayManager->HideAllPopups();
720     auto host = GetHost();
721     CHECK_NULL_VOID(host);
722     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
723     CHECK_NULL_VOID(layoutProp);
724     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
725     if (showInSubWindow) {
726         auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(Container::CurrentId());
727         CHECK_NULL_VOID(subwindow);
728         subwindow->HidePopupNG(targetNodeId_);
729     }
730 }
731 
732 
UpdateText(const RefPtr<UINode> & node,const RefPtr<PopupTheme> & popupTheme)733 void BubblePattern::UpdateText(const RefPtr<UINode>& node, const RefPtr<PopupTheme>& popupTheme)
734 {
735     if (node->GetTag() == V2::TEXT_ETS_TAG) {
736         auto textNode = DynamicCast<FrameNode>(node);
737         CHECK_NULL_VOID(textNode);
738         auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
739         CHECK_NULL_VOID(textLayoutProperty);
740         auto parentNode = node->GetParent();
741         if (parentNode && parentNode->GetTag() == V2::BUTTON_ETS_TAG &&
742             !(Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
743             textLayoutProperty->UpdateTextColor(popupTheme->GetButtonFontColor());
744         } else if (!isSetMessageColor_) {
745             if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
746                 textLayoutProperty->UpdateTextColor(popupTheme->GetFontColor());
747             } else {
748                 textLayoutProperty->UpdateTextColor(popupTheme->GetFontPrimaryColor());
749             }
750         }
751         textNode->MarkModifyDone();
752     } else {
753         for (const auto& childNode : node->GetChildren()) {
754             UpdateText(childNode, popupTheme);
755         }
756     }
757 }
758 
DumpInfo()759 void BubblePattern::DumpInfo()
760 {
761     DumpLog::GetInstance().AddDesc("enableArrow: " + std::to_string(dumpInfo_.enableArrow));
762     DumpLog::GetInstance().AddDesc("mask: " + std::to_string(dumpInfo_.mask));
763     DumpLog::GetInstance().AddDesc("targetTag: " + dumpInfo_.targetNode + ", targetID: "
764         + std::to_string(dumpInfo_.targetID));
765     DumpLog::GetInstance().AddDesc("targetOffset: " + dumpInfo_.targetOffset.ToString());
766     DumpLog::GetInstance().AddDesc("targetSize: " + dumpInfo_.targetOffset.ToString());
767     DumpLog::GetInstance().AddDesc("touchRegion: " + dumpInfo_.touchRegion.ToString());
768     DumpLog::GetInstance().AddDesc("avoid top: " + std::to_string(dumpInfo_.top)
769         + ", bottom: " + std::to_string(dumpInfo_.bottom));
770     DumpLog::GetInstance().AddDesc("userOffset: " + dumpInfo_.userOffset.ToString());
771     DumpLog::GetInstance().AddDesc("targetSpace: " + dumpInfo_.targetSpace.ToString());
772     DumpLog::GetInstance().AddDesc("originPlacement: " + dumpInfo_.originPlacement);
773     DumpLog::GetInstance().AddDesc("finalPlacement: " + dumpInfo_.finalPlacement);
774 }
775 
UpdateBubbleText()776 void BubblePattern::UpdateBubbleText()
777 {
778     auto host = GetHost();
779     CHECK_NULL_VOID(host);
780     host->SetNeedCallChildrenUpdate(false);
781     auto context = host->GetContext();
782     CHECK_NULL_VOID(context);
783     auto popupTheme = context->GetTheme<PopupTheme>();
784     CHECK_NULL_VOID(popupTheme);
785     UpdateText(host, popupTheme);
786     host->MarkDirtyNode();
787 }
788 
OnColorConfigurationUpdate()789 void BubblePattern::OnColorConfigurationUpdate()
790 {
791     if (isCustomPopup_) {
792         return;
793     }
794     colorMode_ = SystemProperties::GetColorMode();
795     UpdateBubbleText();
796 }
797 
UpdateAgingTextSize()798 void BubblePattern::UpdateAgingTextSize()
799 {
800     if (isCustomPopup_) {
801         return;
802     }
803     CHECK_NULL_VOID(messageNode_);
804     messageNode_->MarkDirtyNode();
805 }
806 } // namespace OHOS::Ace::NG
807