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 "element_node_iterator_impl.h" 17 namespace OHOS::uitest { 18 using namespace OHOS::Accessibility; 19 ElementNodeIteratorImpl( const std::vector<AccessibilityElementInfo> &elements)20 ElementNodeIteratorImpl::ElementNodeIteratorImpl( 21 const std::vector<AccessibilityElementInfo> &elements) 22 { 23 elementInfoLists_ = std::move(elements); 24 currentIndex_ = -1; 25 topIndex_ = 0; 26 lastCurrentIndex_ = -1; 27 } 28 ElementNodeIteratorImpl()29 ElementNodeIteratorImpl::ElementNodeIteratorImpl() 30 { 31 currentIndex_ = -1; 32 topIndex_ = 0; 33 lastCurrentIndex_ = -1; 34 } 35 ~ElementNodeIteratorImpl()36 ElementNodeIteratorImpl::~ElementNodeIteratorImpl() 37 { 38 elementInfoLists_.clear(); 39 elementToParentIndexMap_.clear(); 40 elementIndexToHierarch_.clear(); 41 visitAndVisibleIndexSet_.clear(); 42 } 43 DFSNextWithInTarget(Widget &widget)44 bool ElementNodeIteratorImpl::DFSNextWithInTarget(Widget &widget) 45 { 46 if (currentIndex_ == topIndex_) { 47 int count = elementInfoLists_[currentIndex_].GetChildCount(); 48 if (count <= 0) { 49 return false; 50 } 51 for (size_t i = currentIndex_ + 1; i < elementInfoLists_.size(); ++i) { 52 if (elementInfoLists_[i].GetAccessibilityId() != elementInfoLists_[currentIndex_].GetChildId(0)) { 53 continue; 54 } 55 elementToParentIndexMap_.emplace(i, currentIndex_); 56 std::string parentHierarchy = elementIndexToHierarch_.at(currentIndex_); 57 currentIndex_ = i; 58 visitAndVisibleIndexSet_.insert(currentIndex_); 59 WrapperElement(widget); 60 widget.SetHierarchy(WidgetHierarchyBuilder::Build(parentHierarchy, 0)); 61 elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 62 return true; 63 } 64 } 65 return VisitNodeByChildAndBrother(widget); 66 } 67 DFSNext(Widget &widget, uint32_t windowId)68 bool ElementNodeIteratorImpl::DFSNext(Widget &widget, uint32_t windowId) 69 { 70 if (IsVisitFinish()) { 71 return false; 72 } 73 74 if (currentIndex_ == -1) { 75 currentIndex_ = 0; 76 elementToParentIndexMap_.emplace(currentIndex_, -1); 77 visitAndVisibleIndexSet_.insert(currentIndex_); 78 WrapperElement(widget); 79 widget.SetHierarchy(ROOT_HIERARCHY + to_string(windowId)); 80 elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 81 return true; 82 } 83 return VisitNodeByChildAndBrother(widget); 84 } 85 IsVisitFinish() const86 bool ElementNodeIteratorImpl::IsVisitFinish() const 87 { 88 return elementInfoLists_.size() == elementToParentIndexMap_.size(); 89 } 90 RestoreNodeIndexByAnchor()91 void ElementNodeIteratorImpl::RestoreNodeIndexByAnchor() 92 { 93 topIndex_ = currentIndex_; 94 lastCurrentIndex_ = currentIndex_; 95 LOG_D("select in widget, store current index is %{public}d", currentIndex_); 96 } 97 ResetNodeIndexToAnchor()98 void ElementNodeIteratorImpl::ResetNodeIndexToAnchor() 99 { 100 topIndex_ = 0; 101 } 102 ClearDFSNext()103 void ElementNodeIteratorImpl::ClearDFSNext() 104 { 105 elementToParentIndexMap_.clear(); 106 elementIndexToHierarch_.clear(); 107 visitAndVisibleIndexSet_.clear(); 108 currentIndex_ = -1; 109 topIndex_ = 0; 110 } 111 RemoveInvisibleWidget()112 void ElementNodeIteratorImpl::RemoveInvisibleWidget() 113 { 114 visitAndVisibleIndexSet_.erase(currentIndex_); 115 } 116 GetTextByKey(const std::string key)117 std::string ElementNodeIteratorImpl::GetTextByKey(const std::string key) 118 { 119 for (auto element : elementInfoLists_) { 120 if (element.GetInspectorKey() == key) { 121 return element.GetContent(); 122 } 123 } 124 return ""; 125 } 126 GenerateNodeHashCode(const AccessibilityElementInfo &element)127 std::string ElementNodeIteratorImpl::GenerateNodeHashCode(const AccessibilityElementInfo &element) 128 { 129 int32_t winId = element.GetWindowId(); 130 int64_t accessId = element.GetAccessibilityId(); 131 std::stringstream hashcodeStr; 132 hashcodeStr << winId; 133 hashcodeStr << ":"; 134 hashcodeStr << accessId; 135 return hashcodeStr.str(); 136 } 137 WrapperElement(Widget &widget)138 void ElementNodeIteratorImpl::WrapperElement(Widget &widget) 139 { 140 AccessibilityElementInfo element = elementInfoLists_[currentIndex_]; 141 WrapperNodeAttrToVec(widget, element); 142 } 143 VisitNodeByChildAndBrother(Widget &widget)144 bool ElementNodeIteratorImpl::VisitNodeByChildAndBrother(Widget &widget) 145 { 146 int childCount = elementInfoLists_[currentIndex_].GetChildCount(); 147 if (childCount > 0) { 148 if (VisitChildren(widget)) { 149 return true; 150 } 151 } 152 153 if (elementToParentIndexMap_.find(currentIndex_) == elementToParentIndexMap_.cend()) { 154 LOG_D("This node has no parent: %{public}s", 155 std::to_string(elementInfoLists_[currentIndex_].GetAccessibilityId()).data()); 156 return false; 157 } 158 int parentIndex = elementToParentIndexMap_.at(currentIndex_); 159 int tempChildIndex = currentIndex_; 160 if (elementToParentIndexMap_.find(topIndex_) == elementToParentIndexMap_.cend()) { 161 LOG_D("This topIndex_ has no parent: %{public}d", topIndex_); 162 return false; 163 } 164 while (parentIndex != elementToParentIndexMap_.at(topIndex_)) { 165 if (VisitBrother(widget, parentIndex, tempChildIndex)) { 166 return true; 167 } 168 if (elementToParentIndexMap_.find(parentIndex) == elementToParentIndexMap_.cend()) { 169 LOG_D("This node has no parent: %{public}s", 170 std::to_string(elementInfoLists_[parentIndex].GetAccessibilityId()).data()); 171 return false; 172 } 173 tempChildIndex = parentIndex; 174 parentIndex = elementToParentIndexMap_.at(parentIndex); 175 } 176 return false; 177 } 178 VisitChildren(Widget& widget)179 bool ElementNodeIteratorImpl::VisitChildren(Widget& widget) 180 { 181 if (visitAndVisibleIndexSet_.find(currentIndex_) == visitAndVisibleIndexSet_.cend()) { 182 LOG_D("node %{public}s is invisible not find its children", 183 std::to_string(elementInfoLists_[currentIndex_].GetAccessibilityId()).data()); 184 return false; 185 } else { 186 for (size_t i = currentIndex_ + 1; i < elementInfoLists_.size(); ++i) { 187 if (elementInfoLists_[i].GetAccessibilityId() != elementInfoLists_[currentIndex_].GetChildId(0)) { 188 continue; 189 } 190 elementToParentIndexMap_.emplace(i, currentIndex_); 191 std::string parentHierarchy = elementIndexToHierarch_.at(currentIndex_); 192 currentIndex_ = i; 193 visitAndVisibleIndexSet_.insert(currentIndex_); 194 WrapperElement(widget); 195 widget.SetHierarchy(WidgetHierarchyBuilder::Build(parentHierarchy, 0)); 196 elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 197 return true; 198 } 199 return false; 200 } 201 } 202 VisitBrother(Widget &widget, int parentIndex, int tempChildIndex)203 bool ElementNodeIteratorImpl::VisitBrother(Widget &widget, int parentIndex, int tempChildIndex) 204 { 205 AccessibilityElementInfo &parentModel = elementInfoLists_[parentIndex]; 206 int parentChildCount = parentModel.GetChildCount(); 207 for (int i = 0; i < parentChildCount; ++i) { 208 if ((parentModel.GetChildId(i) == elementInfoLists_[tempChildIndex].GetAccessibilityId()) && 209 (i < parentChildCount - 1)) { 210 if (parentModel.GetChildId(i + 1) == elementInfoLists_[tempChildIndex + 1].GetAccessibilityId()) { 211 elementToParentIndexMap_.emplace(tempChildIndex + 1, parentIndex); 212 std::string parentHierarchy = elementIndexToHierarch_.at(parentIndex); 213 currentIndex_ = tempChildIndex + 1; 214 visitAndVisibleIndexSet_.insert(currentIndex_); 215 WrapperElement(widget); 216 widget.SetHierarchy(WidgetHierarchyBuilder::Build(parentHierarchy, i + 1)); 217 elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 218 return true; 219 } else { 220 LOG_E("Node error, except: %{public}s, actual is %{public}s", 221 std::to_string(parentModel.GetChildId(i + 1)).data(), 222 std::to_string(elementInfoLists_[tempChildIndex + 1].GetAccessibilityId()).data()); 223 } 224 } 225 } 226 return false; 227 } 228 WrapperNodeAttrToVec(Widget &widget, const AccessibilityElementInfo &element)229 void ElementNodeIteratorImpl::WrapperNodeAttrToVec(Widget &widget, const AccessibilityElementInfo &element) 230 { 231 Accessibility::Rect nodeOriginRect = elementInfoLists_[currentIndex_].GetRectInScreen(); 232 Rect visibleRect{nodeOriginRect.GetLeftTopXScreenPostion(), nodeOriginRect.GetRightBottomXScreenPostion(), 233 nodeOriginRect.GetLeftTopYScreenPostion(), nodeOriginRect.GetRightBottomYScreenPostion()}; 234 widget.SetBounds(visibleRect); 235 widget.SetAttr(UiAttr::ACCESSIBILITY_ID, std::to_string(element.GetAccessibilityId())); 236 widget.SetAttr(UiAttr::ID, element.GetInspectorKey()); 237 widget.SetAttr(UiAttr::TEXT, element.GetContent()); 238 widget.SetAttr(UiAttr::KEY, element.GetInspectorKey()); 239 widget.SetAttr(UiAttr::TYPE, element.GetComponentType()); 240 widget.SetAttr(UiAttr::DESCRIPTION, element.GetDescriptionInfo()); 241 if (element.GetComponentType() == "rootdecortag" || element.GetInspectorKey() == "ContainerModalTitleRow") { 242 widget.SetAttr(UiAttr::TYPE, "DecorBar"); 243 } 244 widget.SetAttr(UiAttr::ENABLED, element.IsEnabled() ? "true" : "false"); 245 widget.SetAttr(UiAttr::FOCUSED, element.IsFocused() ? "true" : "false"); 246 widget.SetAttr(UiAttr::SELECTED, element.IsSelected() ? "true" : "false"); 247 widget.SetAttr(UiAttr::CLICKABLE, "false"); 248 widget.SetAttr(UiAttr::LONG_CLICKABLE, "false"); 249 widget.SetAttr(UiAttr::SCROLLABLE, element.IsScrollable() ? "true" : "false"); 250 widget.SetAttr(UiAttr::CHECKABLE, element.IsCheckable() ? "true" : "false"); 251 widget.SetAttr(UiAttr::CHECKED, element.IsChecked() ? "true" : "false"); 252 widget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(element.GetWindowId())); 253 widget.SetAttr(UiAttr::ZINDEX, std::to_string(element.GetZIndex())); 254 widget.SetAttr(UiAttr::OPACITY, std::to_string(element.GetOpacity())); 255 widget.SetAttr(UiAttr::BACKGROUNDCOLOR, element.GetBackgroundColor()); 256 widget.SetAttr(UiAttr::BACKGROUNDIMAGE, element.GetBackgroundImage()); 257 widget.SetAttr(UiAttr::BLUR, element.GetBlur()); 258 widget.SetAttr(UiAttr::HITTESTBEHAVIOR, element.GetHitTestBehavior()); 259 widget.SetAttr(UiAttr::CLIP, element.GetClip() ? "true" : "false"); 260 stringstream boundStream; 261 boundStream << "[" << visibleRect.left_ << "," << visibleRect.top_ << "][" << visibleRect.right_ << "," 262 << visibleRect.bottom_ << "]"; 263 widget.SetAttr(UiAttr::ORIGBOUNDS, boundStream.str()); 264 widget.SetAttr(UiAttr::HASHCODE, ElementNodeIteratorImpl::GenerateNodeHashCode(element)); 265 if (!element.IsVisible()) { 266 LOG_D("widget %{public}s is not visible", widget.GetAttr(UiAttr::ACCESSIBILITY_ID).data()); 267 } 268 widget.SetAttr(UiAttr::VISIBLE, element.IsVisible() ? "true" : "false"); 269 const auto app = element.GetBundleName(); 270 widget.SetAttr(UiAttr::BUNDLENAME, app); 271 widget.SetAttr(UiAttr::HINT, element.GetHint()); 272 WrapperNodeActionAttrToVec(widget, element); 273 } 274 WrapperNodeActionAttrToVec(Widget &widget, const AccessibilityElementInfo &element)275 void ElementNodeIteratorImpl::WrapperNodeActionAttrToVec(Widget &widget, const AccessibilityElementInfo &element) 276 { 277 auto actions = element.GetActionList(); 278 for (auto &action : actions) { 279 switch (action.GetActionType()) { 280 case ACCESSIBILITY_ACTION_CLICK: 281 widget.SetAttr(UiAttr::CLICKABLE, "true"); 282 break; 283 case ACCESSIBILITY_ACTION_LONG_CLICK: 284 widget.SetAttr(UiAttr::LONG_CLICKABLE, "true"); 285 break; 286 default: 287 break; 288 } 289 } 290 } 291 } // namespace OHOS::uitest