• 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->GetEventHub<EventHub>();
117     CHECK_NULL_VOID(eventHub);
118     OnAreaChangedFunc onAreaChangedFunc = [popupNodeWk = WeakPtr<FrameNode>(host)](const RectF& /* oldRect */,
119                                               const OffsetF& /* oldOrigin */, const RectF& /* rect */,
120                                               const OffsetF& /* origin */) {
121         auto popupNode = popupNodeWk.Upgrade();
122         CHECK_NULL_VOID(popupNode);
123         popupNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
124     };
125     eventHub->AddInnerOnAreaChangedCallback(host->GetId(), std::move(onAreaChangedFunc));
126 
127     halfFoldHoverCallbackId_ =
128         pipelineContext->RegisterHalfFoldHoverChangedCallback([weak = WeakClaim(this)](bool isHalfFoldHover) {
129             auto pattern = weak.Upgrade();
130             CHECK_NULL_VOID(pattern);
131             auto host = pattern->GetHost();
132             CHECK_NULL_VOID(host);
133             AnimationOption option;
134             auto curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(0.35f, 1.0f, 0.0f);
135             option.SetCurve(curve);
136             auto context = host->GetContext();
137             CHECK_NULL_VOID(context);
138             AnimationUtils::Animate(option, [host, context]() {
139                 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
140                 context->FlushUITasks();
141             });
142         });
143 }
144 
OnDetachFromFrameNode(FrameNode * frameNode)145 void BubblePattern::OnDetachFromFrameNode(FrameNode* frameNode)
146 {
147     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
148     CHECK_NULL_VOID(pipeline);
149     pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
150     pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
151     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
152     CHECK_NULL_VOID(targetNode);
153     if (!hasOnAreaChange_) {
154         pipeline->RemoveOnAreaChangeNode(targetNode->GetId());
155     }
156     pipeline->UnRegisterHalfFoldHoverChangedCallback(halfFoldHoverCallbackId_);
157 }
158 
InitTouchEvent()159 void BubblePattern::InitTouchEvent()
160 {
161     auto host = GetHost();
162     CHECK_NULL_VOID(host);
163     auto hub = host->GetEventHub<EventHub>();
164     CHECK_NULL_VOID(hub);
165     auto gestureHub = hub->GetOrCreateGestureEventHub();
166     CHECK_NULL_VOID(gestureHub);
167     if (touchEvent_) {
168         return;
169     }
170     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
171         auto pattern = weak.Upgrade();
172         if (pattern) {
173             pattern->HandleTouchEvent(info);
174         }
175     };
176     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
177     gestureHub->AddTouchEvent(touchEvent_);
178 }
179 
HandleTouchEvent(const TouchEventInfo & info)180 void BubblePattern::HandleTouchEvent(const TouchEventInfo& info)
181 {
182     if (info.GetTouches().empty()) {
183         return;
184     }
185     auto touchType = info.GetTouches().front().GetTouchType();
186     auto clickPos = info.GetTouches().front().GetLocalLocation();
187     if (touchType == TouchType::DOWN) {
188         HandleTouchDown(clickPos);
189     }
190 }
191 
HandleTouchDown(const Offset & clickPosition)192 void BubblePattern::HandleTouchDown(const Offset& clickPosition)
193 {
194     auto host = GetHost();
195     CHECK_NULL_VOID(host);
196     auto bubbleRenderProp = host->GetPaintProperty<BubbleRenderProperty>();
197     CHECK_NULL_VOID(bubbleRenderProp);
198     if (touchRegion_.IsInRegion(PointF(clickPosition.GetX(), clickPosition.GetY()))) {
199         return;
200     }
201     auto autoCancel = bubbleRenderProp->GetAutoCancel().value_or(true);
202     if (autoCancel) {
203         TAG_LOGD(AceLogTag::ACE_DIALOG, "handle popup touch down event");
204         if (!GetInteractiveDismiss()) {
205             return;
206         }
207         if (HasOnWillDismiss()) {
208             auto pipelineNg = host->GetContextRefPtr();
209             CHECK_NULL_VOID(pipelineNg);
210             auto overlayManager = pipelineNg->GetOverlayManager();
211             CHECK_NULL_VOID(overlayManager);
212             overlayManager->SetDismissPopupId(targetNodeId_);
213             CallOnWillDismiss(static_cast<int32_t>(DismissReason::TOUCH_OUTSIDE));
214             return;
215         }
216         PopBubble();
217     }
218 }
219 
RegisterButtonOnHover()220 void BubblePattern::RegisterButtonOnHover()
221 {
222     if (mouseEventInitFlag_) {
223         return;
224     }
225     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
226     CHECK_NULL_VOID(paintProps);
227     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
228     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
229     auto custom = paintProps->GetUseCustom().value_or(false);
230     if (custom) {
231         return;
232     }
233     if (!primaryButtonShow && !secondaryButtonShow) {
234         return;
235     }
236     auto buttonRowNode = GetButtonRowNode();
237     for (const auto& child : buttonRowNode->GetChildren()) {
238         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
239         CHECK_NULL_VOID(buttonNode);
240         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
241             return;
242         }
243         auto inputHub = buttonNode->GetOrCreateInputEventHub();
244         CHECK_NULL_VOID(inputHub);
245         auto mouseTask = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)](bool isHover) {
246             auto pattern = weak.Upgrade();
247             CHECK_NULL_VOID(pattern);
248             auto buttonNode = buttonNodeWK.Upgrade();
249             CHECK_NULL_VOID(buttonNode);
250             pattern->ButtonOnHover(isHover, buttonNode);
251         };
252         auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
253         inputHub->AddOnHoverEvent(mouseEvent);
254     }
255     mouseEventInitFlag_ = true;
256 }
257 
ButtonOnHover(bool isHover,const RefPtr<NG::FrameNode> & buttonNode)258 void BubblePattern::ButtonOnHover(bool isHover, const RefPtr<NG::FrameNode>& buttonNode)
259 {
260     auto renderContext = buttonNode->GetRenderContext();
261     CHECK_NULL_VOID(renderContext);
262     auto pipeline = PipelineBase::GetCurrentContext();
263     CHECK_NULL_VOID(pipeline);
264     auto theme = pipeline->GetTheme<PopupTheme>();
265     CHECK_NULL_VOID(theme);
266     isHover_ = isHover;
267     auto hoverColor = theme->GetButtonHoverColor();
268     auto backgroundColor = theme->GetButtonBackgroundColor();
269     if (isHover) {
270         // normal to hover
271         Animation(renderContext, hoverColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
272     } else {
273         // hover to normal
274         Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
275     }
276 }
277 
RegisterButtonOnTouch()278 void BubblePattern::RegisterButtonOnTouch()
279 {
280     if (touchEventInitFlag_) {
281         return;
282     }
283     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
284     CHECK_NULL_VOID(paintProps);
285     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
286     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
287     auto custom = paintProps->GetUseCustom().value_or(false);
288     if (custom) {
289         return;
290     }
291     if (!primaryButtonShow && !secondaryButtonShow) {
292         return;
293     }
294 
295     auto buttonRowNode = GetButtonRowNode();
296     for (const auto& child : buttonRowNode->GetChildren()) {
297         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
298         CHECK_NULL_VOID(buttonNode);
299         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
300             return;
301         }
302         auto gestureHub = buttonNode->GetOrCreateGestureEventHub();
303         CHECK_NULL_VOID(gestureHub);
304         auto touchCallback = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)]
305             (const TouchEventInfo& info) {
306             auto pattern = weak.Upgrade();
307             CHECK_NULL_VOID(pattern);
308             auto buttonNode = buttonNodeWK.Upgrade();
309             CHECK_NULL_VOID(buttonNode);
310             pattern->ButtonOnPress(info, buttonNode);
311         };
312         auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
313         gestureHub->AddTouchEvent(touchEvent);
314     }
315     touchEventInitFlag_ = true;
316 }
317 
ButtonOnPress(const TouchEventInfo & info,const RefPtr<NG::FrameNode> & buttonNode)318 void BubblePattern::ButtonOnPress(const TouchEventInfo& info, const RefPtr<NG::FrameNode>& buttonNode)
319 {
320     if (info.GetTouches().empty()) {
321         return;
322     }
323     auto touchType = info.GetTouches().front().GetTouchType();
324     auto renderContext = buttonNode->GetRenderContext();
325     CHECK_NULL_VOID(renderContext);
326     auto pipeline = PipelineBase::GetCurrentContext();
327     CHECK_NULL_VOID(pipeline);
328     auto theme = pipeline->GetTheme<PopupTheme>();
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()377 void BubblePattern::PopBubble()
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     CHECK_NULL_VOID(overlayManager);
385     auto popupInfo = overlayManager->GetPopupInfo(targetNodeId_);
386     if (!popupInfo.isCurrentOnShow) {
387         return;
388     }
389     popupInfo.markNeedUpdate = true;
390     CHECK_NULL_VOID(host);
391     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
392     CHECK_NULL_VOID(layoutProp);
393     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
394     if (showInSubWindow) {
395         SubwindowManager::GetInstance()->HidePopupNG(targetNodeId_);
396     } else {
397         overlayManager->HidePopup(targetNodeId_, popupInfo);
398     }
399 }
400 
GetPopupTheme()401 RefPtr<PopupTheme> BubblePattern::GetPopupTheme()
402 {
403     auto pipelineContext = PipelineBase::GetCurrentContext();
404     CHECK_NULL_RETURN(pipelineContext, nullptr);
405     auto popupTheme = pipelineContext->GetTheme<PopupTheme>();
406     CHECK_NULL_RETURN(popupTheme, nullptr);
407     return popupTheme;
408 }
409 
Animation(RefPtr<RenderContext> & renderContext,const Color & endColor,int32_t duration,const RefPtr<Curve> & curve)410 void BubblePattern::Animation(
411     RefPtr<RenderContext>& renderContext, const Color& endColor, int32_t duration, const RefPtr<Curve>& curve)
412 {
413     AnimationOption option = AnimationOption();
414     option.SetCurve(curve);
415     option.SetDuration(duration);
416     option.SetFillMode(FillMode::FORWARDS);
417     AnimationUtils::Animate(
418         option, [buttonContext = renderContext, color = endColor]() { buttonContext->UpdateBackgroundColor(color); });
419 }
420 
PostTask(const TaskExecutor::Task & task,const std::string & name)421 bool BubblePattern::PostTask(const TaskExecutor::Task& task, const std::string& name)
422 {
423     auto pipeline = PipelineBase::GetCurrentContext();
424     CHECK_NULL_RETURN(pipeline, false);
425     auto taskExecutor = pipeline->GetTaskExecutor();
426     CHECK_NULL_RETURN(taskExecutor, false);
427     return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name);
428 }
429 
StartEnteringTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)430 void BubblePattern::StartEnteringTransitionEffects(
431     const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
432 {
433     auto popupId = popupNode->GetId();
434     auto pattern = popupNode->GetPattern<BubblePattern>();
435     pattern->transitionStatus_ = TransitionStatus::ENTERING;
436     auto layoutProp = popupNode->GetLayoutProperty<BubbleLayoutProperty>();
437     CHECK_NULL_VOID(layoutProp);
438     layoutProp->UpdateVisibility(VisibleType::VISIBLE, false);
439     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
440     auto isBlock = layoutProp->GetBlockEventValue(true);
441     auto& renderContext = popupNode->GetRenderContext();
442     renderContext->SetTransitionInCallback(
443         [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock]() {
444             auto pattern = weak.Upgrade();
445             CHECK_NULL_VOID(pattern);
446             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
447                 return;
448             }
449             pattern->transitionStatus_ = TransitionStatus::NORMAL;
450             if (showInSubWindow) {
451                 std::vector<Rect> rects;
452                 if (!isBlock) {
453                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
454                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
455                     rects.emplace_back(rect);
456                 } else {
457                     auto parentWindowRect = pattern->GetHostWindowRect();
458                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
459                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
460                     rects.emplace_back(parentWindowRect);
461                     rects.emplace_back(rect);
462                 }
463                 auto subWindowMgr = SubwindowManager::GetInstance();
464                 subWindowMgr->SetHotAreas(rects, SubwindowType::TYPE_POPUP, popupId, pattern->GetContainerId());
465             }
466             if (finish) {
467                 finish();
468             }
469         });
470 }
471 
StartExitingTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)472 void BubblePattern::StartExitingTransitionEffects(
473     const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
474 {
475     auto pattern = popupNode->GetPattern<BubblePattern>();
476     pattern->transitionStatus_ = TransitionStatus::EXITING;
477     auto layoutProperty = popupNode->GetLayoutProperty();
478     layoutProperty->UpdateVisibility(VisibleType::INVISIBLE, true);
479     auto renderContext = popupNode->GetRenderContext();
480     renderContext->SetTransitionOutCallback(
481         [weak = WeakClaim(this), finish]() {
482             auto pattern = weak.Upgrade();
483             CHECK_NULL_VOID(pattern);
484             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
485                 return;
486             }
487             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
488             if (finish) {
489                 finish();
490             }
491         });
492 }
493 
StartEnteringAnimation(std::function<void ()> finish)494 void BubblePattern::StartEnteringAnimation(std::function<void()> finish)
495 {
496     if (!arrowPlacement_.has_value()) {
497         delayShow_ = true;
498         finish_ = finish;
499         return;
500     }
501     if (IsOnShow()) {
502         return;
503     }
504 
505     if (transitionStatus_ == TransitionStatus::INVISIABLE) {
506         ResetToInvisible();
507     }
508 
509     StartOffsetEnteringAnimation();
510     if (finish) {
511         StartAlphaEnteringAnimation(finish);
512     } else {
513         StartAlphaEnteringAnimation(finish_);
514     }
515 }
516 
StartOffsetEnteringAnimation()517 void BubblePattern::StartOffsetEnteringAnimation()
518 {
519     AnimationOption optionPosition;
520     optionPosition.SetDuration(ENTRY_ANIMATION_DURATION);
521     optionPosition.SetCurve(Curves::FRICTION);
522     AnimationUtils::Animate(
523         optionPosition,
524         [weak = WeakClaim(this)]() {
525             auto pattern = weak.Upgrade();
526             CHECK_NULL_VOID(pattern);
527             auto renderContext = pattern->GetRenderContext();
528             CHECK_NULL_VOID(renderContext);
529             renderContext->UpdateOffset(OffsetT<Dimension>());
530             renderContext->SyncGeometryProperties(nullptr);
531         },
532         nullptr);
533 }
534 
StartAlphaEnteringAnimation(std::function<void ()> finish)535 void BubblePattern::StartAlphaEnteringAnimation(std::function<void()> finish)
536 {
537     AnimationOption optionAlpha;
538     optionAlpha.SetDuration(ENTRY_ANIMATION_DURATION);
539     optionAlpha.SetCurve(Curves::SHARP);
540     auto host = GetHost();
541     auto popupId = host->GetId();
542     CHECK_NULL_VOID(host);
543     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
544     CHECK_NULL_VOID(layoutProp);
545     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
546     auto isBlock = layoutProp->GetBlockEventValue(true);
547     AnimationUtils::Animate(
548         optionAlpha,
549         [weak = WeakClaim(this)]() {
550             auto pattern = weak.Upgrade();
551             CHECK_NULL_VOID(pattern);
552             pattern->transitionStatus_ = TransitionStatus::ENTERING;
553             auto renderContext = pattern->GetRenderContext();
554             CHECK_NULL_VOID(renderContext);
555             renderContext->UpdateOpacity(VISIABLE_ALPHA);
556         },
557         [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock]() {
558             auto pattern = weak.Upgrade();
559             CHECK_NULL_VOID(pattern);
560             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
561                 return;
562             }
563             pattern->transitionStatus_ = TransitionStatus::NORMAL;
564             if (showInSubWindow) {
565                 std::vector<Rect> rects;
566                 if (!isBlock) {
567                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
568                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
569                     rects.emplace_back(rect);
570                 } else {
571                     auto parentWindowRect = pattern->GetHostWindowRect();
572                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
573                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
574                     rects.emplace_back(parentWindowRect);
575                     rects.emplace_back(rect);
576                 }
577                 auto subWindowMgr = SubwindowManager::GetInstance();
578                 subWindowMgr->SetHotAreas(rects, SubwindowType::TYPE_POPUP, popupId, pattern->GetContainerId());
579             }
580             if (finish) {
581                 finish();
582             }
583         });
584 }
585 
StartExitingAnimation(std::function<void ()> finish)586 void BubblePattern::StartExitingAnimation(std::function<void()> finish)
587 {
588     StartOffsetExitingAnimation();
589     StartAlphaExitingAnimation(finish);
590 }
591 
StartOffsetExitingAnimation()592 void BubblePattern::StartOffsetExitingAnimation()
593 {
594     AnimationOption optionPosition;
595     optionPosition.SetDuration(EXIT_ANIMATION_DURATION);
596     optionPosition.SetCurve(Curves::FRICTION);
597     AnimationUtils::Animate(
598         optionPosition,
599         [weak = WeakClaim(this)]() {
600             auto pattern = weak.Upgrade();
601             CHECK_NULL_VOID(pattern);
602             auto renderContext = pattern->GetRenderContext();
603             CHECK_NULL_VOID(renderContext);
604             renderContext->UpdateOffset(pattern->GetInvisibleOffset());
605             renderContext->SyncGeometryProperties(nullptr);
606         },
607         nullptr);
608 }
609 
StartAlphaExitingAnimation(std::function<void ()> finish)610 void BubblePattern::StartAlphaExitingAnimation(std::function<void()> finish)
611 {
612     AnimationOption optionAlpha;
613     optionAlpha.SetDuration(EXIT_ANIMATION_DURATION);
614     optionAlpha.SetCurve(Curves::SHARP);
615     AnimationUtils::Animate(
616         optionAlpha,
617         [weak = WeakClaim(this)]() {
618             auto pattern = weak.Upgrade();
619             CHECK_NULL_VOID(pattern);
620             pattern->transitionStatus_ = TransitionStatus::EXITING;
621             auto renderContext = pattern->GetRenderContext();
622             CHECK_NULL_VOID(renderContext);
623             renderContext->UpdateOpacity(INVISIABLE_ALPHA);
624         },
625         [weak = WeakClaim(this), finish]() {
626             auto pattern = weak.Upgrade();
627             CHECK_NULL_VOID(pattern);
628             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
629                 return;
630             }
631             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
632             if (finish) {
633                 finish();
634             }
635         });
636 }
637 
IsOnShow()638 bool BubblePattern::IsOnShow()
639 {
640     return (transitionStatus_ == TransitionStatus::ENTERING) || (transitionStatus_ == TransitionStatus::NORMAL);
641 }
642 
IsExiting()643 bool BubblePattern::IsExiting()
644 {
645     return transitionStatus_ == TransitionStatus::EXITING;
646 }
647 
GetInvisibleOffset()648 OffsetT<Dimension> BubblePattern::GetInvisibleOffset()
649 {
650     if (!arrowPlacement_.has_value()) {
651         return OffsetT<Dimension>();
652     }
653 
654     OffsetT<Dimension> offset;
655     switch (arrowPlacement_.value()) {
656         case Placement::LEFT:
657         case Placement::LEFT_TOP:
658         case Placement::LEFT_BOTTOM:
659             offset.AddX(INVISIABLE_OFFSET);
660             break;
661         case Placement::RIGHT:
662         case Placement::RIGHT_TOP:
663         case Placement::RIGHT_BOTTOM:
664             offset.AddX(INVISIABLE_OFFSET * -1);
665             break;
666         case Placement::TOP:
667         case Placement::TOP_LEFT:
668         case Placement::TOP_RIGHT:
669             offset.AddY(INVISIABLE_OFFSET);
670             break;
671         case Placement::BOTTOM:
672         case Placement::BOTTOM_LEFT:
673         case Placement::BOTTOM_RIGHT:
674             offset.AddY(INVISIABLE_OFFSET * -1);
675             break;
676         default:
677             break;
678     }
679     return offset;
680 }
681 
GetRenderContext()682 RefPtr<RenderContext> BubblePattern::GetRenderContext()
683 {
684     auto frameNode = GetHost();
685     CHECK_NULL_RETURN(frameNode, nullptr);
686     return frameNode->GetRenderContext();
687 }
688 
ResetToInvisible()689 void BubblePattern::ResetToInvisible()
690 {
691     auto renderContext = GetRenderContext();
692     CHECK_NULL_VOID(renderContext);
693 
694     renderContext->UpdateOpacity(INVISIABLE_ALPHA);
695     renderContext->UpdateOffset(GetInvisibleOffset());
696     renderContext->SyncGeometryProperties(nullptr);
697 }
698 
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)699 void BubblePattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
700 {
701     TAG_LOGD(AceLogTag::ACE_OVERLAY, "Popup OnWindowSizeChanged, reason: %d", type);
702     switch (type) {
703         case WindowSizeChangeReason::UNDEFINED:
704         case WindowSizeChangeReason::MOVE:
705         case WindowSizeChangeReason::RESIZE:
706         case WindowSizeChangeReason::DRAG_START:
707         case WindowSizeChangeReason::DRAG:
708         case WindowSizeChangeReason::DRAG_END: {
709             break;
710         }
711         default: {
712             auto host = GetHost();
713             CHECK_NULL_VOID(host);
714             auto pipelineNg = host->GetContextRefPtr();
715             CHECK_NULL_VOID(pipelineNg);
716             auto overlayManager = pipelineNg->GetOverlayManager();
717             CHECK_NULL_VOID(overlayManager);
718             overlayManager->HideAllPopups();
719             auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
720             CHECK_NULL_VOID(layoutProp);
721             auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
722             if (showInSubWindow) {
723                 auto subwindow = SubwindowManager::GetInstance()->GetSubwindowByType(
724                     pipelineNg->GetInstanceId(), SubwindowType::TYPE_POPUP);
725                 CHECK_NULL_VOID(subwindow);
726                 subwindow->HidePopupNG(targetNodeId_);
727             }
728         }
729     }
730 }
731 
OnWindowHide()732 void BubblePattern::OnWindowHide()
733 {
734     TAG_LOGD(AceLogTag::ACE_OVERLAY, "Popup OnWindowHide start");
735     auto host = GetHost();
736     CHECK_NULL_VOID(host);
737     auto pipelineNg = host->GetContextRefPtr();
738     CHECK_NULL_VOID(pipelineNg);
739     auto overlayManager = pipelineNg->GetOverlayManager();
740     CHECK_NULL_VOID(overlayManager);
741     overlayManager->HideAllPopups();
742     CHECK_NULL_VOID(host);
743     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
744     CHECK_NULL_VOID(layoutProp);
745     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
746     if (showInSubWindow) {
747         auto subwindow = SubwindowManager::GetInstance()->GetSubwindowByType(
748             pipelineNg->GetInstanceId(), SubwindowType::TYPE_POPUP);
749         CHECK_NULL_VOID(subwindow);
750         subwindow->HidePopupNG(targetNodeId_);
751     }
752 }
753 
754 
UpdateText(const RefPtr<UINode> & node,const RefPtr<PopupTheme> & popupTheme)755 void BubblePattern::UpdateText(const RefPtr<UINode>& node, const RefPtr<PopupTheme>& popupTheme)
756 {
757     if (node->GetTag() == V2::TEXT_ETS_TAG) {
758         auto textNode = DynamicCast<FrameNode>(node);
759         CHECK_NULL_VOID(textNode);
760         auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
761         CHECK_NULL_VOID(textLayoutProperty);
762         auto parentNode = node->GetParent();
763         if (parentNode && parentNode->GetTag() == V2::BUTTON_ETS_TAG &&
764             !(Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
765             textLayoutProperty->UpdateTextColor(popupTheme->GetButtonFontColor());
766         } else if (!isSetMessageColor_) {
767             if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
768                 textLayoutProperty->UpdateTextColor(popupTheme->GetFontColor());
769             } else {
770                 textLayoutProperty->UpdateTextColor(popupTheme->GetFontPrimaryColor());
771             }
772         }
773         textNode->MarkModifyDone();
774         textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
775     } else {
776         for (const auto& childNode : node->GetChildren()) {
777             UpdateText(childNode, popupTheme);
778         }
779     }
780 }
781 
DumpInfo()782 void BubblePattern::DumpInfo()
783 {
784     DumpLog::GetInstance().AddDesc("enableArrow: " + std::to_string(dumpInfo_.enableArrow));
785     DumpLog::GetInstance().AddDesc("mask: " + std::to_string(dumpInfo_.mask));
786     DumpLog::GetInstance().AddDesc("targetTag: " + dumpInfo_.targetNode + ", targetID: "
787         + std::to_string(dumpInfo_.targetID));
788     DumpLog::GetInstance().AddDesc("targetOffset: " + dumpInfo_.targetOffset.ToString());
789     DumpLog::GetInstance().AddDesc("targetSize: " + dumpInfo_.targetSize.ToString());
790     DumpLog::GetInstance().AddDesc("touchRegion: " + dumpInfo_.touchRegion.ToString());
791     DumpLog::GetInstance().AddDesc("avoid top: " + std::to_string(dumpInfo_.top)
792         + ", bottom: " + std::to_string(dumpInfo_.bottom));
793     DumpLog::GetInstance().AddDesc("userOffset: " + dumpInfo_.userOffset.ToString());
794     DumpLog::GetInstance().AddDesc("targetSpace: " + dumpInfo_.targetSpace.ToString());
795     DumpLog::GetInstance().AddDesc("originPlacement: " + dumpInfo_.originPlacement);
796     DumpLog::GetInstance().AddDesc("finalPlacement: " + dumpInfo_.finalPlacement);
797     DumpLog::GetInstance().AddDesc("enableHoverMode: " + std::to_string(dumpInfo_.enableHoverMode));
798     DumpLog::GetInstance().AddDesc("avoidKeyboard: " + std::to_string(dumpInfo_.avoidKeyboard));
799 }
800 
UpdateBubbleText()801 void BubblePattern::UpdateBubbleText()
802 {
803     auto host = GetHost();
804     CHECK_NULL_VOID(host);
805     host->SetNeedCallChildrenUpdate(false);
806     auto context = host->GetContext();
807     CHECK_NULL_VOID(context);
808     auto popupTheme = context->GetTheme<PopupTheme>();
809     CHECK_NULL_VOID(popupTheme);
810     UpdateText(host, popupTheme);
811     host->MarkDirtyNode();
812 }
813 
OnColorConfigurationUpdate()814 void BubblePattern::OnColorConfigurationUpdate()
815 {
816     if (isCustomPopup_) {
817         return;
818     }
819     auto context = GetContext();
820     CHECK_NULL_VOID(context);
821     colorMode_ = context->GetColorMode();
822     UpdateBubbleText();
823 }
824 
UpdateAgingTextSize()825 void BubblePattern::UpdateAgingTextSize()
826 {
827     if (isCustomPopup_) {
828         return;
829     }
830     CHECK_NULL_VOID(messageNode_);
831     messageNode_->MarkDirtyNode();
832 }
833 } // namespace OHOS::Ace::NG
834