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