• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/manager/avoid_info/avoid_info_manager.h"
17 
18 #include "core/components_ng/base/frame_node.h"
19 #include "core/components_ng/pattern/container_modal/enhance/container_modal_view_enhance.h"
20 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
21 
22 namespace OHOS::Ace::NG {
23 
ToString() const24 std::string ContainerModalAvoidInfo::ToString() const
25 {
26     std::string str("needAvoid: ");
27     str.append(needAvoid ? "true" : "false");
28     str.append(", titleHeight: ");
29     str.append(std::to_string(titleHeight));
30     str.append(", rect: ");
31     str.append(controlBottonsRect.ToString());
32     return str;
33 }
34 
RegisterListenerIfNeeded()35 void AvoidInfoManager::RegisterListenerIfNeeded()
36 {
37     if (hasRegisterListener_) {
38         return;
39     }
40 
41     auto pipeline = pipeline_.Upgrade();
42     CHECK_NULL_VOID(pipeline);
43     auto container = Container::GetContainer(instanceId_);
44     CHECK_NULL_VOID(container);
45     if (!container->IsUIExtensionWindow()) {
46         auto containerModalListener =
47             [weakMgr = WeakClaim(this)](const RectF&, const RectF&) {
48                 auto mgr = weakMgr.Upgrade();
49                 CHECK_NULL_VOID(mgr);
50                 mgr->OnContainerModalInfoChange();
51             };
52         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "AvoidInfoManager register listener");
53         containerModalListenerId_ = ContainerModalViewEnhance::AddButtonsRectChangeListener(
54             AceType::RawPtr(pipeline), std::move(containerModalListener));
55         // init avoid info
56         ContainerModalAvoidInfo info;
57         GetContainerModalAvoidInfo(info);
58         SetAvoidInfo(info);
59         hasRegisterListener_ = true;
60         return;
61     }
62 
63     if (!registerUECConsumerCallback_ || !requestAvoidInfoCallback_) {
64         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "AvoidInfoManager did not set register callback.");
65         return;
66     }
67 
68     auto consumer = [weakMgr = WeakClaim(this), instanceId = instanceId_](const AAFwk::Want& data) -> int32_t {
69         ContainerScope scope(instanceId);
70         auto mgr = weakMgr.Upgrade();
71         CHECK_NULL_RETURN(mgr, 0);
72         return mgr->OnUECAvoidInfoReceived(data);
73     };
74     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "AvoidInfoManager register listener for UEC");
75     registerUECConsumerCallback_(std::move(consumer));
76     // request avoid info for first time.
77     requestAvoidInfoCallback_();
78     hasRegisterListener_ = true;
79 }
80 
OnContainerModalInfoChange()81 void AvoidInfoManager::OnContainerModalInfoChange()
82 {
83     ContainerModalAvoidInfo newInfo;
84     GetContainerModalAvoidInfo(newInfo);
85     bool needNotify = CheckIfNeedNotifyAvoidInfoChange(avoidInfo_, newInfo);
86     SetAvoidInfo(newInfo);
87     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "AvoidInfo change to: %{public}s", newInfo.ToString().c_str());
88     if (needNotify) {
89         OnAvoidInfoChange(newInfo);
90     }
91 }
92 
OnUECAvoidInfoReceived(const AAFwk::Want & data)93 int32_t AvoidInfoManager::OnUECAvoidInfoReceived(const AAFwk::Want& data)
94 {
95     ContainerModalAvoidInfo info;
96     if (!ParseAvoidInfo(data, info)) {
97         return -1;
98     }
99     SetAvoidInfoForUEC(info);
100     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "[UEC]AvoidInfo change to: %{public}s", info.ToString().c_str());
101     OnAvoidInfoChange(info);
102     return 0;
103 }
104 
UnregisterListenerIfNeeded()105 void AvoidInfoManager::UnregisterListenerIfNeeded()
106 {
107     if (!hasRegisterListener_) {
108         return;
109     }
110 
111     auto container = Container::GetContainer(instanceId_);
112     CHECK_NULL_VOID(container);
113     if (container->IsUIExtensionWindow()) {
114         hasRegisterListener_ = false;
115         return;
116     }
117 
118     auto pipeline = pipeline_.Upgrade();
119     CHECK_NULL_VOID(pipeline);
120     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "AvoidInfoManager unregister listener");
121     ContainerModalViewEnhance::RemoveButtonsRectChangeListener(
122         AceType::RawPtr(pipeline), containerModalListenerId_);
123     hasRegisterListener_ = false;
124 }
125 
GetContainerModalTitleHeight()126 int32_t AvoidInfoManager::GetContainerModalTitleHeight()
127 {
128     auto container = Container::GetContainer(instanceId_);
129     CHECK_NULL_RETURN(container, 0);
130     if (container->IsUIExtensionWindow()) {
131         return avoidInfoForUEC_.titleHeight;
132     }
133     return avoidInfo_.titleHeight;
134 }
135 
GetContainerModalButtonsRect(RectF & containerModal,RectF & buttonsRect)136 bool AvoidInfoManager::GetContainerModalButtonsRect(RectF& containerModal, RectF& buttonsRect)
137 {
138     auto container = Container::GetContainer(instanceId_);
139     CHECK_NULL_RETURN(container, false);
140     RectF* rect = nullptr;
141     if (container->IsUIExtensionWindow()) {
142         rect = &avoidInfoForUEC_.controlBottonsRect;
143     } else {
144         rect = &avoidInfo_.controlBottonsRect;
145     }
146     if (rect->IsValid()) {
147         buttonsRect = *rect;
148         return true;
149     }
150     return false;
151 }
152 
NeedAvoidContainerModal()153 bool AvoidInfoManager::NeedAvoidContainerModal()
154 {
155     auto container = Container::GetContainer(instanceId_);
156     CHECK_NULL_RETURN(container, false);
157     if (container->IsUIExtensionWindow()) {
158         return avoidInfoForUEC_.needAvoid;
159     }
160     return avoidInfo_.needAvoid;
161 }
162 
OnAvoidInfoChange(const ContainerModalAvoidInfo & info)163 void AvoidInfoManager::OnAvoidInfoChange(const ContainerModalAvoidInfo& info)
164 {
165     for (auto& weak : listeners_) {
166         auto listener = weak.Upgrade();
167         if (listener) {
168             listener->OnAvoidInfoChange(info);
169         }
170     }
171 }
172 
AddAvoidInfoListener(WeakPtr<IAvoidInfoListener> listener)173 void AvoidInfoManager::AddAvoidInfoListener(WeakPtr<IAvoidInfoListener> listener)
174 {
175     RegisterListenerIfNeeded();
176     listeners_.emplace(listener);
177 }
178 
RemoveAvoidInfoListener(WeakPtr<IAvoidInfoListener> listener)179 void AvoidInfoManager::RemoveAvoidInfoListener(WeakPtr<IAvoidInfoListener> listener)
180 {
181     auto it = listeners_.find(listener);
182     if (it != listeners_.end()) {
183         listeners_.erase(it);
184     }
185     if (listeners_.empty()) {
186         UnregisterListenerIfNeeded();
187     }
188 }
189 
GetContainerModalAvoidInfoForUEC(const RefPtr<FrameNode> & uecNode,ContainerModalAvoidInfo & info)190 void AvoidInfoManager::GetContainerModalAvoidInfoForUEC(const RefPtr<FrameNode>& uecNode, ContainerModalAvoidInfo& info)
191 {
192     info.needAvoid = false;
193     CHECK_NULL_VOID(uecNode);
194     auto context = uecNode->GetContext();
195     CHECK_NULL_VOID(context);
196     if (context->GetContainerCustomTitleVisible() || !context->GetContainerControlButtonVisible()) {
197         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "uec don't need avoid control button");
198         return;
199     }
200     auto globalOffset = uecNode->GetPaintRectOffsetNG();
201     auto uecGeometryNode = uecNode->GetGeometryNode();
202     CHECK_NULL_VOID(uecGeometryNode);
203     auto uecRect = uecGeometryNode->GetFrameRect();
204     uecRect.SetOffset(globalOffset);
205     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "uec rect: %{public}s", uecRect.ToString().c_str());
206     RectF buttonsRect;
207     RectF containerModal;
208     if (!context->GetContainerModalButtonsRect(containerModal, buttonsRect)) {
209         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "failed to get buttonRect");
210         return;
211     }
212     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "control button rect: %{public}s", buttonsRect.ToString().c_str());
213     auto height = context->GetContainerModalTitleHeight();
214     if (height <= 0) {
215         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "failed to get titleHeight");
216         return;
217     }
218     if (!uecRect.IsIntersectWith(buttonsRect)) {
219         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "UEC isn't intersect with control button");
220         return;
221     }
222     info.needAvoid = true;
223     info.titleHeight = height;
224     info.controlBottonsRect = uecRect.IntersectRectT(buttonsRect);
225     info.controlBottonsRect -= globalOffset;
226 }
227 
CheckIfNeedNotifyAvoidInfoChange(const ContainerModalAvoidInfo & preInfo,const ContainerModalAvoidInfo & curInfo)228 bool AvoidInfoManager::CheckIfNeedNotifyAvoidInfoChange(
229     const ContainerModalAvoidInfo& preInfo, const ContainerModalAvoidInfo& curInfo)
230 {
231     return (curInfo.needAvoid != preInfo.needAvoid) ||
232         (curInfo.needAvoid && (curInfo.titleHeight != preInfo.titleHeight ||
233             curInfo.controlBottonsRect != preInfo.controlBottonsRect));
234 }
235 
GetContainerModalAvoidInfo(ContainerModalAvoidInfo & info)236 void AvoidInfoManager::GetContainerModalAvoidInfo(ContainerModalAvoidInfo& info)
237 {
238     info.needAvoid = false;
239     auto context = PipelineContext::GetContextByContainerId(instanceId_);
240     CHECK_NULL_VOID(context);
241     if (context->GetContainerCustomTitleVisible() || !context->GetContainerControlButtonVisible()) {
242         return;
243     }
244     RectF buttonsRect;
245     RectF containerModal;
246     if (!context->GetContainerModalButtonsRect(containerModal, buttonsRect)) {
247         return;
248     }
249     auto height = context->GetContainerModalTitleHeight();
250     if (height <= 0) {
251         return;
252     }
253     info.needAvoid = true;
254     info.titleHeight = height;
255     info.controlBottonsRect = buttonsRect;
256 }
257 } // namespace OHOS::Ace::NG
258