• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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/app_bar/atomic_service_pattern.h"
16 #include <string>
17 
18 #include "core/components_ng/pattern/button/button_pattern.h"
19 #include "core/components_ng/pattern/divider/divider_render_property.h"
20 #include "core/components_ng/pattern/image/image_layout_property.h"
21 #include "core/components_ng/pattern/image/image_render_property.h"
22 #include "core/components_ng/base/inspector.h"
23 #include "core/components_ng/pattern/app_bar/app_bar_view.h"
24 namespace OHOS::Ace::NG {
25 constexpr int32_t ATOMIC_SERVICE_MIN_SIZE = 2;
26 constexpr int32_t FIRST_OVERLAY_INDEX = 1;
27 
28 std::atomic<int32_t> g_nextListenerId = 1;
29 
30 std::function<void(RefPtr<FrameNode> host, std::optional<bool> settedColorMode)>
31     AtomicServicePattern::beforeCreateLayoutBuilder_ = nullptr;
32 
RegisterBeforeCreateLayoutBuilder(std::function<void (RefPtr<FrameNode> host,std::optional<bool> settedColorMode)> beforeCreateLayoutBuilder)33 void AtomicServicePattern::RegisterBeforeCreateLayoutBuilder(
34     std::function<void(RefPtr<FrameNode> host, std::optional<bool> settedColorMode)> beforeCreateLayoutBuilder)
35 {
36     beforeCreateLayoutBuilder_ = beforeCreateLayoutBuilder;
37 }
38 
BeforeCreateLayoutWrapper()39 void AtomicServicePattern::BeforeCreateLayoutWrapper()
40 {
41     // before create layout builder for cj frontend
42     if (beforeCreateLayoutBuilder_) {
43         beforeCreateLayoutBuilder_(GetHost(), settedColorMode);
44         return;
45     }
46     MenuBarSafeAreaCallBack();
47     ContentSafeAreaCallBack();
48     ColorConfigurationCallBack();
49 }
50 
MenuBarSafeAreaCallBack()51 void AtomicServicePattern::MenuBarSafeAreaCallBack()
52 {
53     auto pipeline = PipelineContext::GetCurrentContext();
54     CHECK_NULL_VOID(pipeline);
55     auto theme = pipeline->GetTheme<AppBarTheme>();
56     CHECK_NULL_VOID(theme);
57     auto host = GetHost();
58     CHECK_NULL_VOID(host);
59     auto manager = pipeline->GetSafeAreaManager();
60     CHECK_NULL_VOID(manager);
61     manager->SetIsAtomicService(true);
62     manager->AddGeoRestoreNode(host);
63     auto systemSafeArea = manager->GetSystemSafeArea();
64     auto menuSafeTopValue = systemSafeArea.top_.Length();
65     auto menuSafeTopVp = Dimension(menuSafeTopValue, DimensionUnit::PX).ConvertToVp();
66     auto customAppBar = GetJSAppBarContainer();
67     CHECK_NULL_VOID(customAppBar);
68     customAppBar->FireCustomCallback(ARKUI_APP_BAR_MENU_SAFE_AREA, std::to_string(menuSafeTopVp));
69 }
70 
ContentSafeAreaCallBack()71 void AtomicServicePattern::ContentSafeAreaCallBack()
72 {
73     auto pipeline = PipelineContext::GetCurrentContext();
74     CHECK_NULL_VOID(pipeline);
75     auto safeArea = pipeline->GetSafeArea();
76     auto manager = pipeline->GetSafeAreaManager();
77     CHECK_NULL_VOID(manager);
78     if (manager->KeyboardSafeAreaEnabled()) {
79         safeArea.bottom_ = safeArea.bottom_.Combine(manager->GetKeyboardInset());
80     }
81     auto left = Dimension(safeArea.left_.Length(), DimensionUnit::PX).ConvertToVp();
82     auto right = Dimension(safeArea.right_.Length(), DimensionUnit::PX).ConvertToVp();
83     auto top = Dimension(safeArea.top_.Length(), DimensionUnit::PX).ConvertToVp();
84     auto bottom = Dimension(safeArea.bottom_.Length(), DimensionUnit::PX).ConvertToVp();
85     auto customAppBar = GetJSAppBarContainer();
86     CHECK_NULL_VOID(customAppBar);
87     std::vector<float> values = { top, left, right, bottom };
88     std::string result;
89     for (size_t i = 0; i < values.size(); ++i) {
90         result += std::to_string(values[i]);
91         if (i < values.size() - 1) {
92             result += "|";
93         }
94     }
95     customAppBar->FireCustomCallback(ARKUI_APP_BAR_CONTENT_SAFE_AREA, result);
96 }
97 
ColorConfigurationCallBack()98 void AtomicServicePattern::ColorConfigurationCallBack()
99 {
100     auto customAppBar = GetJSAppBarContainer();
101     CHECK_NULL_VOID(customAppBar);
102     auto context = GetContext();
103     CHECK_NULL_VOID(context);
104     customAppBar->FireCustomCallback(ARKUI_APP_BAR_COLOR_CONFIGURATION,
105         settedColorMode.has_value() ? !settedColorMode.value() : context->GetColorMode() == ColorMode::DARK);
106 }
107 
AppInfoCallBack()108 void AtomicServicePattern::AppInfoCallBack()
109 {
110     auto atom = GetHost();
111     CHECK_NULL_VOID(atom);
112     auto pipeline = atom->GetContextRefPtr();
113     CHECK_NULL_VOID(pipeline);
114     auto themeManager = pipeline->GetThemeManager();
115     CHECK_NULL_VOID(themeManager);
116     auto themeConstants = themeManager->GetThemeConstants();
117     CHECK_NULL_VOID(themeConstants);
118     auto windowManager = pipeline->GetWindowManager();
119     CHECK_NULL_VOID(windowManager);
120     auto customAppBar = GetJSAppBarContainer();
121     CHECK_NULL_VOID(customAppBar);
122     auto id = windowManager->GetAppIconId();
123     auto pixelMap = themeConstants->GetPixelMap(id);
124     if (pixelMap) {
125         const RefPtr<PixelMap> icon = PixelMap::CreatePixelMap(&pixelMap);
126         customAppBar->FireAppIconCallback(icon);
127     } else {
128         TAG_LOGW(AceLogTag::ACE_APPBAR, "App bar Cannot get pixelmap, try media path.");
129     }
130     auto result = AceApplicationInfo::GetInstance().GetProcessName() + "|" +
131                   themeConstants->GetString(windowManager->GetAppLabelId());
132     customAppBar->FireCustomCallback(ARKUI_APP_BAR_BAR_INFO, result);
133 }
134 
AppScreenCallBack()135 void AtomicServicePattern::AppScreenCallBack()
136 {
137     auto customAppBar = GetJSAppBarContainer();
138     CHECK_NULL_VOID(customAppBar);
139     auto container = Container::Current();
140     CHECK_NULL_VOID(container);
141     customAppBar->FireCustomCallback(ARKUI_APP_BAR_SCREEN, container->UIExtensionIsHalfScreen());
142 }
143 
SetOnBackPressedConsumed()144 void AtomicServicePattern::SetOnBackPressedConsumed()
145 {
146     if (onBackPressedConsumed_.has_value()) {
147         onBackPressedConsumed_ = true;
148     }
149 }
150 
OnBackPressedCallback()151 bool AtomicServicePattern::OnBackPressedCallback()
152 {
153     auto customAppBar = GetJSAppBarContainer();
154     CHECK_NULL_RETURN(customAppBar, false);
155     onBackPressedConsumed_ = false;
156     customAppBar->FireCustomCallback(ARKUI_APP_BAR_ON_BACK_PRESSED, true);
157     bool consumed = onBackPressedConsumed_.value();
158     onBackPressedConsumed_.reset();
159     return consumed;
160 }
161 
AppBgColorCallBack()162 void AtomicServicePattern::AppBgColorCallBack()
163 {
164     auto host = GetHost();
165     CHECK_NULL_VOID(host);
166     auto pipeline = host->GetContextRefPtr();
167     CHECK_NULL_VOID(pipeline);
168     auto customAppBar = GetJSAppBarContainer();
169     CHECK_NULL_VOID(customAppBar);
170     customAppBar->FireCustomCallback(ARKUI_APP_BG_COLOR, pipeline->GetAppBgColor().ColorToString());
171 }
172 
UpdateLayoutMargin()173 void AtomicServicePattern::UpdateLayoutMargin()
174 {
175     auto pipeline = PipelineContext::GetCurrentContext();
176     CHECK_NULL_VOID(pipeline);
177     auto safeArea = pipeline->GetSafeArea();
178     auto atom = GetHost();
179     CHECK_NULL_VOID(atom);
180     MarginProperty margin;
181     margin.left = CalcLength(safeArea.left_.Length());
182     margin.right = CalcLength(safeArea.right_.Length());
183     margin.top = CalcLength(safeArea.top_.Length());
184     margin.bottom = CalcLength(safeArea.bottom_.Length());
185     // update stage margin
186     auto stage = GetContent();
187     CHECK_NULL_VOID(stage);
188     auto layoutProperty = stage->GetLayoutProperty();
189     CHECK_NULL_VOID(layoutProperty);
190     layoutProperty->UpdateMargin(margin);
191     stage->MarkModifyDone();
192     stage->MarkDirtyNode();
193 }
194 
UpdateOverlayLayout()195 void AtomicServicePattern::UpdateOverlayLayout()
196 {
197     auto atom = GetHost();
198     CHECK_NULL_VOID(atom);
199     if (atom->GetChildren().size() <= ATOMIC_SERVICE_MIN_SIZE) {
200         return;
201     }
202     for (int index = FIRST_OVERLAY_INDEX;
203         index <= static_cast<int32_t>(atom->GetChildren().size()) - ATOMIC_SERVICE_MIN_SIZE; index++) {
204         auto overlay = AceType::DynamicCast<FrameNode>(atom->GetChildAtIndex(index));
205         CHECK_NULL_VOID(overlay);
206         auto overlayRender = overlay->GetRenderContext();
207         overlayRender->UpdatePosition(OffsetT<Dimension>());
208         overlay->MarkModifyDone();
209         overlay->MarkDirtyNode();
210     }
211 }
212 
OnAttachToFrameNode()213 void AtomicServicePattern::OnAttachToFrameNode()
214 {
215     auto host = GetHost();
216     CHECK_NULL_VOID(host);
217     host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
218     AppBgColorCallBack();
219 }
220 
OnColorConfigurationUpdate()221 void AtomicServicePattern::OnColorConfigurationUpdate()
222 {
223     AppBgColorCallBack();
224     ColorConfigurationCallBack();
225 }
226 
OnLanguageConfigurationUpdate()227 void AtomicServicePattern::OnLanguageConfigurationUpdate()
228 {
229     AppInfoCallBack();
230 }
231 
GetJSAppBarContainer()232 RefPtr<CustomAppBarNode> AtomicServicePattern::GetJSAppBarContainer()
233 {
234     auto customAppBarNode = NG::ViewStackProcessor::GetInstance()->GetCustomAppBarNode();
235     return AceType::DynamicCast<CustomAppBarNode>(customAppBarNode);
236 }
237 
GetStageNodeWrapper()238 RefPtr<FrameNode> AtomicServicePattern::GetStageNodeWrapper()
239 {
240     return NG::Inspector::GetFrameNodeByKey("AtomicServiceStageId");
241 }
242 
GetContent()243 RefPtr<FrameNode> AtomicServicePattern::GetContent()
244 {
245     auto stageNodeWrapper = GetStageNodeWrapper();
246     CHECK_NULL_RETURN(stageNodeWrapper, nullptr);
247     return AceType::DynamicCast<FrameNode>(stageNodeWrapper->GetChildAtIndex(0));
248 }
249 
GetMenuBarRow()250 RefPtr<FrameNode> AtomicServicePattern::GetMenuBarRow()
251 {
252     return NG::Inspector::GetFrameNodeByKey("AtomicServiceMenubarRowId");
253 }
254 
GetMenuBar()255 RefPtr<FrameNode> AtomicServicePattern::GetMenuBar()
256 {
257     return NG::Inspector::GetFrameNodeByKey("AtomicServiceMenubarId");
258 }
259 
GetMenuButton()260 RefPtr<FrameNode> AtomicServicePattern::GetMenuButton()
261 {
262     return NG::Inspector::GetFrameNodeByKey("AtomicServiceMenuId");
263 }
264 
GetDivider()265 RefPtr<FrameNode> AtomicServicePattern::GetDivider()
266 {
267     return NG::Inspector::GetFrameNodeByKey("AtomicServiceDividerId");
268 }
269 
GetCloseButton()270 RefPtr<FrameNode> AtomicServicePattern::GetCloseButton()
271 {
272     return NG::Inspector::GetFrameNodeByKey("AtomicServiceCloseId");
273 }
274 
GetMenuIcon()275 RefPtr<FrameNode> AtomicServicePattern::GetMenuIcon()
276 {
277     return NG::Inspector::GetFrameNodeByKey("AtomicServiceMenuIconId");
278 }
279 
GetCloseIcon()280 RefPtr<FrameNode> AtomicServicePattern::GetCloseIcon()
281 {
282     return NG::Inspector::GetFrameNodeByKey("AtomicServiceCloseIconId");
283 }
284 
UpdateColor(std::optional<bool> isLight)285 void AtomicServicePattern::UpdateColor(std::optional<bool> isLight)
286 {
287     auto pipeline = PipelineContext::GetCurrentContext();
288     CHECK_NULL_VOID(pipeline);
289     auto theme = pipeline->GetTheme<AppBarTheme>();
290     if (!(isLight.has_value())) {
291         isLight = pipeline->GetColorMode() != ColorMode::DARK;
292     }
293     auto menuButton = GetMenuButton();
294     UpdateButtonColor(theme, menuButton, isLight.value());
295     auto divider = GetDivider();
296     UpdateDividerColor(theme, divider, isLight.value());
297     auto closeButton = GetCloseButton();
298     UpdateButtonColor(theme, closeButton, isLight.value());
299 
300     auto menuIcon = GetMenuIcon();
301     UpdateIconColor(theme, menuIcon, isLight.value());
302     auto closeIcon = GetCloseIcon();
303     UpdateIconColor(theme, closeIcon, isLight.value());
304 }
305 
UpdateMenuBarColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & menuBar,bool isLight)306 void AtomicServicePattern::UpdateMenuBarColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& menuBar, bool isLight)
307 {
308     CHECK_NULL_VOID(theme);
309     CHECK_NULL_VOID(menuBar);
310     auto renderContext = menuBar->GetRenderContext();
311     // background effect、border color
312     EffectOption option;
313     BorderColorProperty borderColor;
314     option.radius = theme->GetBlurRadius();
315     if (isLight) {
316         option.color = theme->GetBlurColorLight();
317         borderColor.SetColor(theme->GetBorderColorLight());
318     } else {
319         option.color = theme->GetBlurColorDark();
320         borderColor.SetColor(theme->GetBorderColorDark());
321     }
322     renderContext->UpdateBackgroundEffect(option);
323     renderContext->UpdateBorderColor(borderColor);
324 
325     menuBar->MarkModifyDone();
326     menuBar->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
327 }
328 
UpdateButtonColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & button,bool isLight)329 void AtomicServicePattern::UpdateButtonColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& button, bool isLight)
330 {
331     CHECK_NULL_VOID(theme);
332     CHECK_NULL_VOID(button);
333     // pressed color
334     auto buttonPattern = button->GetPattern<ButtonPattern>();
335     CHECK_NULL_VOID(buttonPattern);
336     if (isLight) {
337         buttonPattern->SetClickedColor(theme->GetClickEffectColorLight());
338     } else {
339         buttonPattern->SetClickedColor(theme->GetClickEffectColorDark());
340     }
341     // focus border color
342     if (isLight) {
343         buttonPattern->SetFocusBorderColor(theme->GetFocusedOutlineColorLight());
344     } else {
345         buttonPattern->SetFocusBorderColor(theme->GetFocusedOutlineColorDark());
346     }
347 
348     button->MarkModifyDone();
349     button->MarkDirtyNode();
350 }
351 
UpdateDividerColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & divider,bool isLight)352 void AtomicServicePattern::UpdateDividerColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& divider, bool isLight)
353 {
354     CHECK_NULL_VOID(theme);
355     CHECK_NULL_VOID(divider);
356 
357     auto renderProperty = divider->GetPaintProperty<DividerRenderProperty>();
358     if (isLight) {
359         renderProperty->UpdateDividerColor(theme->GetDividerColorLight());
360     } else {
361         renderProperty->UpdateDividerColor(theme->GetDividerColorDark());
362     }
363 
364     divider->MarkModifyDone();
365     divider->MarkDirtyNode();
366 }
367 
UpdateIconColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & icon,bool isLight)368 void AtomicServicePattern::UpdateIconColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& icon, bool isLight)
369 {
370     CHECK_NULL_VOID(theme);
371     CHECK_NULL_VOID(icon);
372     // fill color
373     auto color = isLight ? theme->GetIconColorLight() : theme->GetIconColorDark();
374     ACE_UPDATE_NODE_PAINT_PROPERTY(ImageRenderProperty, SvgFillColor, color, icon);
375     ACE_UPDATE_NODE_RENDER_CONTEXT(ForegroundColor, color, icon);
376     icon->MarkModifyDone();
377     icon->MarkDirtyNode();
378 }
379 
UpdateLayout()380 void AtomicServicePattern::UpdateLayout()
381 {
382     auto pipeline = PipelineContext::GetCurrentContext();
383     CHECK_NULL_VOID(pipeline);
384     auto theme = pipeline->GetTheme<AppBarTheme>();
385     CHECK_NULL_VOID(theme);
386     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
387 
388     auto menuBar = GetMenuBar();
389     UpdateMenuBarLayout(theme, menuBar, isRtl);
390 
391     auto menuButton = GetMenuButton();
392     UpdateButtonLayout(theme, menuButton, !isRtl);
393     auto closeButton = GetCloseButton();
394     UpdateButtonLayout(theme, closeButton, isRtl);
395 
396     auto menuIcon = GetMenuIcon();
397     UpdateIconLayout(theme, menuIcon, !isRtl);
398     auto closeIcon = GetCloseIcon();
399     UpdateIconLayout(theme, closeIcon, isRtl);
400 }
401 
UpdateMenuBarLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & menuBar,bool isRtl)402 void AtomicServicePattern::UpdateMenuBarLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& menuBar, bool isRtl)
403 {
404     CHECK_NULL_VOID(theme);
405     CHECK_NULL_VOID(menuBar);
406 
407     MarginProperty margin;
408     auto pipeline = PipelineContext::GetCurrentContext();
409     CHECK_NULL_VOID(pipeline);
410     auto safeArea = pipeline->GetSafeArea();
411 
412     Dimension safeAreaLeft(pipeline->Px2VpWithCurrentDensity(safeArea.left_.Length()), DimensionUnit::VP);
413     Dimension safeAreaRight(pipeline->Px2VpWithCurrentDensity(safeArea.right_.Length()), DimensionUnit::VP);
414 
415     if (isRtl) {
416         margin.left = CalcLength(theme->GetMenuBarRightMargin() + safeAreaLeft);
417         margin.right = CalcLength(theme->GetMenuBarLeftMargin() + safeAreaRight);
418     } else {
419         margin.left = CalcLength(theme->GetMenuBarLeftMargin() + safeAreaLeft);
420         margin.right = CalcLength(theme->GetMenuBarRightMargin() + safeAreaRight);
421     }
422     menuBar->GetLayoutProperty<LinearLayoutProperty>()->UpdateMargin(margin);
423 
424     menuBar->MarkModifyDone();
425     menuBar->MarkDirtyNode();
426 }
427 
UpdateButtonLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & button,bool isLeft)428 void AtomicServicePattern::UpdateButtonLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& button, bool isLeft)
429 {
430     CHECK_NULL_VOID(theme);
431     CHECK_NULL_VOID(button);
432 
433     auto bent = theme->GetBentRadius();
434     auto rightAngle = theme->GetRightAngle();
435     auto leftBorderRadius = BorderRadiusProperty(bent, rightAngle, rightAngle, bent);
436     auto rightBorderRadius = BorderRadiusProperty(rightAngle, bent, bent, rightAngle);
437 
438     auto layoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
439     layoutProperty->UpdateBorderRadius(isLeft ? leftBorderRadius : rightBorderRadius);
440 
441     button->MarkModifyDone();
442     button->MarkDirtyNode();
443 }
444 
UpdateIconLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & icon,bool isLeft)445 void AtomicServicePattern::UpdateIconLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& icon, bool isLeft)
446 {
447     CHECK_NULL_VOID(theme);
448     CHECK_NULL_VOID(icon);
449 
450     MarginProperty margin;
451     margin.top = CalcLength(theme->GetIconVerticalMargin());
452     margin.bottom = CalcLength(theme->GetIconVerticalMargin());
453     if (isLeft) {
454         margin.left = CalcLength(theme->GetIconOutsideMargin());
455         margin.right = CalcLength(theme->GetIconInsideMargin());
456     } else {
457         margin.left = CalcLength(theme->GetIconInsideMargin());
458         margin.right = CalcLength(theme->GetIconOutsideMargin());
459     }
460     auto layoutProperty = icon->GetLayoutProperty<ImageLayoutProperty>();
461     CHECK_NULL_VOID(layoutProperty);
462     layoutProperty->UpdateMargin(margin);
463 
464     icon->MarkModifyDone();
465     icon->MarkDirtyNode();
466 }
467 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)468 bool AtomicServicePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
469 {
470     auto atom = GetHost();
471     CHECK_NULL_RETURN(atom, false);
472     auto pipeline = atom->GetContextRefPtr();
473     CHECK_NULL_RETURN(pipeline, false);
474     pipeline->AddAfterLayoutTask([weak = WeakClaim(this)]() {
475         auto pattern = weak.Upgrade();
476         CHECK_NULL_VOID(pattern);
477         pattern->CallRectChange();
478     });
479     return false;
480 }
481 
AddRectChangeListener(std::function<void (const RectF & rect)> && listener)482 int32_t AtomicServicePattern::AddRectChangeListener(std::function<void(const RectF& rect)>&& listener)
483 {
484     auto id = g_nextListenerId.fetch_add(1);
485     rectChangeListeners_.emplace(id, listener);
486     return id;
487 }
488 
RemoveRectChangeListener(int32_t id)489 void AtomicServicePattern::RemoveRectChangeListener(int32_t id)
490 {
491     auto it = rectChangeListeners_.find(id);
492     if (it != rectChangeListeners_.end()) {
493         rectChangeListeners_.erase(it);
494     }
495 }
496 
NotifyRectChange(const RectF & rect)497 void AtomicServicePattern::NotifyRectChange(const RectF& rect)
498 {
499     for (auto& pair : rectChangeListeners_) {
500         if (pair.second) {
501             pair.second(rect);
502         }
503     }
504 }
505 
CallRectChange()506 void AtomicServicePattern::CallRectChange()
507 {
508     auto host = GetHost();
509     CHECK_NULL_VOID(host);
510     auto pipeline = host->GetContextRefPtr();
511     CHECK_NULL_VOID(pipeline);
512     auto container = Container::GetContainer(pipeline->GetInstanceId());
513     CHECK_NULL_VOID(container);
514     auto appbar = container->GetAppBar();
515     CHECK_NULL_VOID(appbar);
516     auto rect = appbar->GetAppBarRect();
517     if (!rect.has_value()) {
518         TAG_LOGW(AceLogTag::ACE_APPBAR, "Get rect of app bar failed, app bar is hidden");
519         return;
520     }
521     if (appBarRect_.has_value() && appBarRect_.value() == rect.value()) {
522         TAG_LOGD(AceLogTag::ACE_APPBAR, "App bar rect is not changed, no need to notify");
523         return;
524     }
525     NotifyRectChange(rect.value());
526     appBarRect_ = rect;
527 }
528 } // namespace OHOS::Ace::NG
529