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 
16 #include "core/components_ng/pattern/ui_extension/ui_extension_manager.h"
17 
18 #include "adapter/ohos/entrance/ace_container.h"
19 #include "core/components_ng/pattern/ui_extension/security_ui_extension_pattern.h"
20 #include "core/components_ng/pattern/ui_extension/ui_extension_pattern.h"
21 
22 namespace OHOS::Ace::NG {
UIExtensionIdUtility()23 UIExtensionIdUtility::UIExtensionIdUtility() {}
24 
~UIExtensionIdUtility()25 UIExtensionIdUtility::~UIExtensionIdUtility() {}
26 
ApplyExtensionId()27 int32_t UIExtensionIdUtility::ApplyExtensionId()
28 {
29     std::lock_guard<std::mutex> poolMutex(poolMutex_);
30     for (int32_t index = 0; index < UI_EXTENSION_ID_FIRST_MAX; index++) {
31         if (!idPool_.test(index)) {
32             idPool_.set(index, 1);
33             return index + 1;
34         }
35     }
36     return UI_EXTENSION_UNKNOW_ID;
37 }
38 
RecycleExtensionId(int32_t id)39 void UIExtensionIdUtility::RecycleExtensionId(int32_t id)
40 {
41     std::lock_guard<std::mutex> poolMutex(poolMutex_);
42     if ((id > UI_EXTENSION_UNKNOW_ID) && (id <= UI_EXTENSION_ID_FIRST_MAX)) {
43         idPool_.set(id - 1, 0);
44     }
45 }
46 
RegisterUIExtensionInFocus(const WeakPtr<UIExtensionPattern> & uiExtensionFocused,const WeakPtr<SessionWrapper> & sessionWrapper)47 void UIExtensionManager::RegisterUIExtensionInFocus(
48     const WeakPtr<UIExtensionPattern>& uiExtensionFocused, const WeakPtr<SessionWrapper>& sessionWrapper)
49 {
50     securityUiExtensionFocused_ = nullptr;
51     uiExtensionFocused_ = uiExtensionFocused;
52     sessionWrapper_ = sessionWrapper;
53 }
54 
RegisterSecurityUIExtensionInFocus(const WeakPtr<SecurityUIExtensionPattern> & uiExtensionFocused,const WeakPtr<SessionWrapper> & sessionWrapper)55 void UIExtensionManager::RegisterSecurityUIExtensionInFocus(
56     const WeakPtr<SecurityUIExtensionPattern>& uiExtensionFocused,
57     const WeakPtr<SessionWrapper>& sessionWrapper)
58 {
59     uiExtensionFocused_ = nullptr;
60     securityUiExtensionFocused_ = uiExtensionFocused;
61     sessionWrapper_ = sessionWrapper;
62 }
63 
OnBackPressed()64 bool UIExtensionManager::OnBackPressed()
65 {
66     auto sessionWrapper = sessionWrapper_.Upgrade();
67     if (sessionWrapper) {
68         return sessionWrapper->NotifyBackPressedSync();
69     }
70 
71     return HandleUnfocusedModalUecBackPressed();
72 }
73 
DumpUIExt()74 void UIExtensionManager::DumpUIExt()
75 {
76     auto pattern = uiExtensionFocused_.Upgrade();
77     CHECK_NULL_VOID(pattern);
78     pattern->DumpOthers();
79 }
80 
HandleUnfocusedModalUecBackPressed()81 bool UIExtensionManager::HandleUnfocusedModalUecBackPressed()
82 {
83     RefPtr<SessionWrapper> session = nullptr;
84     {
85         std::lock_guard<std::mutex> aliveUIExtensionMutex(aliveUIExtensionMutex_);
86         for (auto item = aliveUIExtensions_.rbegin(); item != aliveUIExtensions_.rend(); ++item) {
87             auto uiExtension = item->second.Upgrade();
88             if (uiExtension == nullptr) {
89                 continue;
90             }
91 
92             if (!uiExtension->IsModalUec()) {
93                 continue;
94             }
95 
96             bool isForeground = uiExtension->IsForeground();
97             bool isLastModal = IsLastModalUec(uiExtension->GetHost());
98             TAG_LOGI(AceLogTag::ACE_UIEXTENSIONCOMPONENT, "HandleUnfocusedModalUecBackPressed,"
99                 " sessionId: %{public}d, isForeground: %{public}d, isLastModal: %{public}d",
100                 uiExtension->GetSessionId(), isForeground, isLastModal);
101             if (!isForeground || !isLastModal) {
102                 continue;
103             }
104 
105             session = uiExtension->GetSessionWrapper();
106             break;
107         }
108     }
109 
110     if (session) {
111         return session->NotifyBackPressedSync();
112     }
113 
114     return false;
115 }
116 
IsLastModalUec(const RefPtr<FrameNode> & frameNode)117 bool UIExtensionManager::IsLastModalUec(const RefPtr<FrameNode>& frameNode)
118 {
119     CHECK_NULL_RETURN(frameNode, false);
120     auto parentNode = frameNode->GetParent();
121     CHECK_NULL_RETURN(parentNode, false);
122     if (parentNode->GetTag() != V2::MODAL_PAGE_TAG) {
123         TAG_LOGW(AceLogTag::ACE_UIEXTENSIONCOMPONENT,
124             "parentNode not modalPage, parentNode tag: %{public}s",
125             parentNode->GetTag().c_str());
126         return false;
127     }
128 
129     auto grandpaNode = parentNode->GetParent();
130     if (grandpaNode == nullptr) {
131         TAG_LOGW(AceLogTag::ACE_UIEXTENSIONCOMPONENT, "ModalPage no parent.");
132         return false;
133     }
134 
135     auto lastChild = grandpaNode->GetLastChild();
136     if (lastChild == nullptr) {
137         TAG_LOGW(AceLogTag::ACE_UIEXTENSIONCOMPONENT, "LastChild is null.");
138         return false;
139     }
140 
141     if (lastChild != parentNode) {
142         TAG_LOGW(AceLogTag::ACE_UIEXTENSIONCOMPONENT, "ModalPage is not the last "
143             "child of rootNode, lastChild tag: %{public}s, parentNode tag: %{public}s",
144             lastChild->GetTag().c_str(), parentNode->GetTag().c_str());
145         return false;
146     }
147 
148     return true;
149 }
150 
IsWrapExtensionAbilityId(int64_t elementId)151 bool UIExtensionManager::IsWrapExtensionAbilityId(int64_t elementId)
152 {
153     return elementId > UI_EXTENSION_OFFSET_MIN;
154 }
155 
SendAccessibilityEventInfo(const Accessibility::AccessibilityEventInfo & eventInfo,int64_t uiExtensionOffset,const RefPtr<PipelineBase> & pipeline)156 bool UIExtensionManager::SendAccessibilityEventInfo(const Accessibility::AccessibilityEventInfo& eventInfo,
157     int64_t uiExtensionOffset, const RefPtr<PipelineBase>& pipeline)
158 {
159     CHECK_NULL_RETURN(pipeline, false);
160     auto instanceId = pipeline->GetInstanceId();
161     auto window = Platform::AceContainer::GetUIWindow(instanceId);
162     CHECK_NULL_RETURN(window, false);
163     OHOS::Rosen::WMError ret = window->TransferAccessibilityEvent(eventInfo, uiExtensionOffset);
164     return ret == OHOS::Rosen::WMError::WM_OK;
165 }
166 
UnWrapExtensionAbilityId(int64_t extensionOffset,int64_t elementId)167 std::pair<int64_t, int64_t> UIExtensionManager::UnWrapExtensionAbilityId(int64_t extensionOffset, int64_t elementId)
168 {
169     if (extensionOffset == 0) {
170         return std::pair<int64_t, int64_t>(0, 0);
171     }
172     int64_t index = elementId / extensionOffset;
173     int64_t abilityId = elementId % extensionOffset;
174     return std::pair<int64_t, int64_t>(index, abilityId);
175 }
176 
GetFocusUiExtensionNode()177 const RefPtr<FrameNode> UIExtensionManager::GetFocusUiExtensionNode()
178 {
179     auto uiExtensionFocused = uiExtensionFocused_.Upgrade();
180     CHECK_NULL_RETURN(uiExtensionFocused, nullptr);
181     return uiExtensionFocused->GetHost();
182 }
183 
ApplyExtensionId()184 int32_t UIExtensionManager::ApplyExtensionId()
185 {
186     return UIExtensionIdUtility::GetInstance().ApplyExtensionId();
187 }
188 
RecycleExtensionId(int32_t id)189 void UIExtensionManager::RecycleExtensionId(int32_t id)
190 {
191     UIExtensionIdUtility::GetInstance().RecycleExtensionId(id);
192 }
193 
AddAliveUIExtension(int32_t nodeId,const WeakPtr<UIExtensionPattern> & uiExtension)194 void UIExtensionManager::AddAliveUIExtension(int32_t nodeId, const WeakPtr<UIExtensionPattern>& uiExtension)
195 {
196     std::lock_guard<std::mutex> aliveUIExtensionMutex(aliveUIExtensionMutex_);
197     aliveUIExtensions_.try_emplace(nodeId, uiExtension);
198 }
199 
AddAliveUIExtension(int32_t nodeId,const WeakPtr<SecurityUIExtensionPattern> & uiExtension)200 void UIExtensionManager::AddAliveUIExtension(
201     int32_t nodeId, const WeakPtr<SecurityUIExtensionPattern>& uiExtension)
202 {
203     aliveSecurityUIExtensions_.try_emplace(nodeId, uiExtension);
204 }
205 
TransferOriginAvoidArea(const Rosen::AvoidArea & avoidArea,uint32_t type)206 void UIExtensionManager::TransferOriginAvoidArea(const Rosen::AvoidArea& avoidArea, uint32_t type)
207 {
208     for (const auto& it : aliveUIExtensions_) {
209         auto uiExtension = it.second.Upgrade();
210         if (uiExtension) {
211             uiExtension->DispatchOriginAvoidArea(avoidArea, type);
212         }
213     }
214 
215     for (const auto& it : aliveSecurityUIExtensions_) {
216         auto uiExtension = it.second.Upgrade();
217         if (uiExtension) {
218             uiExtension->DispatchOriginAvoidArea(avoidArea, type);
219         }
220     }
221 }
222 
RemoveDestroyedUIExtension(int32_t nodeId)223 void UIExtensionManager::RemoveDestroyedUIExtension(int32_t nodeId)
224 {
225     {
226         std::lock_guard<std::mutex> aliveUIExtensionMutex(aliveUIExtensionMutex_);
227         auto it = aliveUIExtensions_.find(nodeId);
228         if (it != aliveUIExtensions_.end()) {
229             aliveUIExtensions_.erase(nodeId);
230         }
231     }
232 
233     auto iter = aliveSecurityUIExtensions_.find(nodeId);
234     if (iter != aliveSecurityUIExtensions_.end()) {
235         aliveSecurityUIExtensions_.erase(nodeId);
236     }
237 }
238 
NotifyOccupiedAreaChangeInfo(const sptr<Rosen::OccupiedAreaChangeInfo> & info)239 bool UIExtensionManager::NotifyOccupiedAreaChangeInfo(const sptr<Rosen::OccupiedAreaChangeInfo>& info)
240 {
241     int32_t keyboardHeight = static_cast<int32_t>(info->rect_.height_);
242     if (keyboardHeight != 0) {
243         auto sessionWrapper = sessionWrapper_.Upgrade();
244         return sessionWrapper && sessionWrapper->NotifyOccupiedAreaChangeInfo(info, true);
245     }
246     // keyboardHeight is 0, broadcast it.
247     bool ret = false;
248     for (const auto& it : aliveUIExtensions_) {
249         auto uiExtension = it.second.Upgrade();
250         if (uiExtension) {
251             auto session = uiExtension->GetSessionWrapper();
252             if (session && session->IsSessionValid()) {
253                 ret |= session->NotifyOccupiedAreaChangeInfo(info);
254             }
255         }
256     }
257     return ret;
258 }
259 
NotifySizeChangeReason(WindowSizeChangeReason type,const std::shared_ptr<Rosen::RSTransaction> & rsTransaction)260 void UIExtensionManager::NotifySizeChangeReason(
261     WindowSizeChangeReason type, const std::shared_ptr<Rosen::RSTransaction>& rsTransaction)
262 {
263     for (const auto& it : aliveUIExtensions_) {
264         auto uiExtension = it.second.Upgrade();
265         if (uiExtension) {
266             uiExtension->NotifySizeChangeReason(type, rsTransaction);
267         }
268     }
269 
270     for (const auto& it : aliveSecurityUIExtensions_) {
271         auto uiExtension = it.second.Upgrade();
272         if (uiExtension) {
273             uiExtension->NotifySizeChangeReason(type, rsTransaction);
274         }
275     }
276 }
277 
IsShowPlaceholder(int32_t nodeId)278 bool UIExtensionManager::IsShowPlaceholder(int32_t nodeId)
279 {
280     auto it = aliveUIExtensions_.find(nodeId);
281     if (it != aliveUIExtensions_.end()) {
282         auto uiExtension = it->second.Upgrade();
283         if (uiExtension) {
284             return uiExtension->IsShowPlaceholder();
285         }
286     }
287     return true;
288 }
289 } // namespace OHOS::Ace::NG
290