• 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_ACCESSIBILITY_UTILS_ACCESSIBILITY_MANAGER_UTILS_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_ACCESSIBILITY_UTILS_ACCESSIBILITY_MANAGER_UTILS_H
18 
19 #include <map>
20 
21 #include "base/memory/ace_type.h"
22 #include "core/components_ng/pattern/pattern.h"
23 #include "core/pipeline_ng/pipeline_context.h"
24 
25 namespace OHOS::Ace::NG {
26 
27 class FrameNode;
28 
29 class PageEventController {
30 public:
Add(const RefPtr<FrameNode> & frameNode)31     void Add(const RefPtr<FrameNode>& frameNode)
32     {
33         CHECK_NULL_VOID(frameNode);
34         auto pipeline = frameNode->GetContextRefPtr();
35         CHECK_NULL_VOID(pipeline);
36         auto containerId = pipeline->GetInstanceId();
37         TAG_LOGD(AceLogTag::ACE_ACCESSIBILITY,
38             "AddToPageEventController containerId %{public}d, node %{public}"
39             PRId64, containerId, frameNode->GetAccessibilityId());
40 
41         auto it = controller_.find(containerId);
42         if (it != controller_.end()) {
43             it->second[WeakPtr(frameNode)] = false;
44         } else {
45             controller_.emplace(
46                 containerId, std::map<WeakPtr<FrameNode>, bool> {{ WeakPtr(frameNode), false }});
47         }
48     }
49 
Delete(const RefPtr<FrameNode> & frameNode)50     bool Delete(const RefPtr<FrameNode>& frameNode)
51     {
52         CHECK_NULL_RETURN(frameNode, false);
53         auto pipeline = frameNode->GetContextRefPtr();
54         CHECK_NULL_RETURN(pipeline, false);
55         auto containerId = pipeline->GetInstanceId();
56         auto it = controller_.find(containerId);
57         if (it != controller_.end()) {
58             auto& controllerMap = it->second;
59             auto mapIt = controllerMap.find(WeakPtr(frameNode));
60             if (mapIt != controllerMap.end()) {
61                 controllerMap.erase(mapIt);
62                 return true;
63             }
64         }
65         return false;
66     }
67 
CheckNode(const RefPtr<FrameNode> & frameNode,bool deleteController)68     bool CheckNode(const RefPtr<FrameNode>& frameNode, bool deleteController)
69     {
70         CHECK_NULL_RETURN(frameNode, false);
71         auto pipeline = frameNode->GetContextRefPtr();
72         CHECK_NULL_RETURN(pipeline, false);
73         auto containerId = pipeline->GetInstanceId();
74         auto it = controller_.find(containerId);
75         if (it != controller_.end()) {
76             auto& controllerMap = it->second;
77             auto mapIt = controllerMap.find(WeakPtr(frameNode));
78             if (mapIt != controllerMap.end()) {
79                 if (deleteController) {
80                     controllerMap.erase(mapIt);
81                 }
82                 return true;
83             }
84         }
85         return false;
86     }
87 
DeleteInstanceNodeAll(const RefPtr<FrameNode> & frameNode)88     void DeleteInstanceNodeAll(const RefPtr<FrameNode>& frameNode)
89     {
90         CHECK_NULL_VOID(frameNode);
91         auto pipeline = frameNode->GetContextRefPtr();
92         CHECK_NULL_VOID(pipeline);
93         auto containerId = pipeline->GetInstanceId();
94         auto it = controller_.find(containerId);
95         if (it != controller_.end()) {
96             auto& controllerMap = it->second;
97             for (auto mapIt = controllerMap.begin(); mapIt != controllerMap.end();) {
98                 if (WeakPtr(frameNode) == mapIt->first) {
99                     mapIt = controllerMap.erase(mapIt);
100                 } else {
101                     ++mapIt;
102                 }
103             }
104         }
105     }
106 
Update()107     void Update()
108     {
109         for (auto it = controller_.begin(); it != controller_.end(); ++it) {
110             auto& controllerMap = it->second;
111             for (auto mapIt = controllerMap.begin(); mapIt != controllerMap.end();) {
112                 auto node = mapIt->first;
113                 auto frameNode = node.Upgrade();
114                 if (!frameNode) {
115                     mapIt = controllerMap.erase(mapIt);
116                 } else {
117                     ++mapIt;
118                 }
119             }
120         }
121     }
122 
CheckEmpty(int32_t containerId)123     bool CheckEmpty(int32_t containerId)
124     {
125         auto it = controller_.find(containerId);
126         if (it != controller_.end()) {
127             auto& controllerMap = it->second;
128             return controllerMap.size() == 0;
129         }
130         return true;
131     }
132 
DeleteInstanceControllerByInstance(int32_t containerId)133     void DeleteInstanceControllerByInstance(int32_t containerId)
134     {
135         auto it = controller_.find(containerId);
136         if (it != controller_.end()) {
137             controller_.erase(it);
138         }
139     }
140 
AddAccessibilityEvent(const int32_t containerId,const int32_t pageId,AccessibilityEvent & event)141     void AddAccessibilityEvent(const int32_t containerId, const int32_t pageId, AccessibilityEvent& event)
142     {
143         TimeStamp now = std::chrono::steady_clock::now();
144         auto& eventList = pageEvent_[containerId];
145         eventList.emplace_back(std::make_tuple(pageId, event, now));
146 
147         CleanExpiredEvents(containerId, now);
148     }
149 
HasAnyAccessibilityEvent(const int32_t containerId)150     bool HasAnyAccessibilityEvent(const int32_t containerId) const
151     {
152         auto mapIt = pageEvent_.find(containerId);
153         if (mapIt == pageEvent_.end()) {
154             return false;
155         }
156         return !mapIt->second.empty();
157     }
158 
HasAccessibilityEvent(const int32_t containerId,const int32_t pageId)159     bool HasAccessibilityEvent(const int32_t containerId, const int32_t pageId) const
160     {
161         auto mapIt = pageEvent_.find(containerId);
162         if (mapIt == pageEvent_.end()) {
163             return false;
164         }
165         const auto& eventList = mapIt->second;
166         return std::any_of(eventList.begin(), eventList.end(),
167             [pageId](const auto& tuple) {
168                 return std::get<0>(tuple) == pageId;
169             });
170     }
171 
ReleaseAccessibilityEvent(const int32_t containerId,const int32_t pageId,std::list<std::pair<int32_t,AccessibilityEvent>> & eventListInput)172     void ReleaseAccessibilityEvent(
173         const int32_t containerId,
174         const int32_t pageId,
175         std::list<std::pair<int32_t, AccessibilityEvent>>& eventListInput)
176     {
177         auto mapIt = pageEvent_.find(containerId);
178         if (mapIt == pageEvent_.end()) {
179             return;
180         }
181         auto& eventList = mapIt->second;
182         for (auto it = eventList.begin(); it != eventList.end();) {
183             if (std::get<0>(*it) == pageId) {
184                 eventListInput.emplace_back(std::make_pair(std::get<0>(*it), std::get<1>(*it)));
185                 it = eventList.erase(it);
186             } else {
187                 ++it;
188             }
189         }
190 
191         if (eventList.empty()) {
192             pageEvent_.erase(mapIt);
193         }
194     }
195 
ReleaseAllAccessibilityEvent(const int32_t containerId,std::list<std::pair<int32_t,AccessibilityEvent>> & eventListInput)196     void ReleaseAllAccessibilityEvent(
197         const int32_t containerId,
198         std::list<std::pair<int32_t,
199         AccessibilityEvent>>& eventListInput)
200     {
201         auto mapIt = pageEvent_.find(containerId);
202         if (mapIt == pageEvent_.end()) {
203             return;
204         }
205         for (auto& tuple : mapIt->second) {
206             eventListInput.emplace_back(std::make_pair(std::get<0>(tuple), std::get<1>(tuple)));
207         }
208 
209         pageEvent_.erase(mapIt);
210     }
211 
212 private:
CleanExpiredEvents(int32_t containerId,TimeStamp now)213     void CleanExpiredEvents(int32_t containerId, TimeStamp now)
214     {
215         auto mapIt = pageEvent_.find(containerId);
216         if (mapIt == pageEvent_.end()) {
217             return;
218         }
219         auto& eventList = mapIt->second;
220         auto isExpired = std::any_of(eventList.begin(), eventList.end(),
221             [&](const auto& tuple) {
222                 uint64_t duration =
223                     static_cast<uint64_t>(
224                         std::chrono::duration_cast<std::chrono::milliseconds>(now - std::get<2>(tuple)).count());
225                 return duration > EXPIRATION_TIME;
226             });
227         if (isExpired) {
228             TAG_LOGI(AceLogTag::ACE_ACCESSIBILITY,
229                 "page cache event expired over %{public}d ms", EXPIRATION_TIME);
230             pageEvent_.erase(mapIt);
231             DeleteInstanceControllerByInstance(containerId); // remove controller
232         }
233     }
234 
235     static const int EXPIRATION_TIME = 5000; // 5s
236     std::map<int32_t, std::map<WeakPtr<FrameNode>, bool>> controller_;
237     // tuple with (pageId, event, timestamp) in different containerId
238     std::map<int32_t, std::list<std::tuple<int32_t, AccessibilityEvent, TimeStamp>>> pageEvent_;
239 };
240 
241 class HoverTransparentCallbackController {
242 public:
AddToHoverTransparentCallbackList(const RefPtr<FrameNode> & frameNode)243     bool AddToHoverTransparentCallbackList(const RefPtr<FrameNode>& frameNode)
244     {
245         UpdateHoverTransparentCallbackList();
246         CHECK_NULL_RETURN(frameNode, false);
247         auto pipeline = frameNode->GetContextRefPtr();
248         CHECK_NULL_RETURN(pipeline, false);
249         auto containerId = pipeline->GetInstanceId();
250         auto it = controller_.find(containerId);
251         if (it != controller_.end()) {
252             auto& controllerList = it->second;
253             for (const auto& nodeWptr : controllerList) {
254                 auto node = nodeWptr.Upgrade();
255                 if (node == nullptr) {
256                     continue;
257                 }
258                 if (node->GetAccessibilityId() == frameNode->GetAccessibilityId()) {
259                     return false;
260                 }
261             }
262             it->second.emplace_back(WeakPtr(frameNode));
263         } else {
264             controller_.emplace(
265                 containerId, std::list<WeakPtr<FrameNode>> { WeakPtr(frameNode) });
266         }
267         return true;
268     }
269 
UpdateHoverTransparentCallbackList()270     void UpdateHoverTransparentCallbackList()
271     {
272         for (auto it = controller_.begin(); it != controller_.end(); ++it) {
273             auto& controllerList = it->second;
274             for (auto controllerListIt = controllerList.begin(); controllerListIt != controllerList.end();) {
275                 auto node = (*controllerListIt).Upgrade();
276                 if (!node) {
277                     controllerListIt = controllerList.erase(controllerListIt);
278                 } else {
279                     ++controllerListIt;
280                 }
281             }
282         }
283     }
284 
IsInHoverTransparentCallbackList(const RefPtr<FrameNode> & frameNode)285     bool IsInHoverTransparentCallbackList(const RefPtr<FrameNode>& frameNode)
286     {
287         UpdateHoverTransparentCallbackList();
288         CHECK_NULL_RETURN(frameNode, false);
289         auto pipeline = frameNode->GetContextRefPtr();
290         CHECK_NULL_RETURN(pipeline, false);
291         auto containerId = pipeline->GetInstanceId();
292         auto it = controller_.find(containerId);
293         if (it == controller_.end()) {
294             return false;
295         }
296         auto& controllerList = it->second;
297         for (const auto& nodeWptr : controllerList) {
298             auto node = nodeWptr.Upgrade();
299             if (!node) {
300                 continue;
301             }
302             if (node->GetAccessibilityId() == frameNode->GetAccessibilityId()) {
303                 return true;
304             }
305         }
306         return false;
307     }
308 
CheckHoverTransparentCallbackListEmpty(int32_t containerId)309     bool CheckHoverTransparentCallbackListEmpty(int32_t containerId)
310     {
311         UpdateHoverTransparentCallbackList();
312         auto it = controller_.find(containerId);
313         if (it != controller_.end()) {
314             return it->second.empty();
315         }
316         return true;
317     }
318 
319 private:
320     std::map<int32_t, std::list<WeakPtr<FrameNode>>> controller_;
321 };
322 
323 } // namespace OHOS::Ace::NG
324 
325 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_ACCESSIBILITY_UTILS_ACCESSIBILITY_MANAGER_UTILS_H
326