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 GenerateNodeHashCode(const AccessibilityElementInfo & element)117 std::string ElementNodeIteratorImpl::GenerateNodeHashCode(const AccessibilityElementInfo &element) 118 { 119 int32_t winId = element.GetWindowId(); 120 int64_t accessId = element.GetAccessibilityId(); 121 std::stringstream hashcodeStr; 122 hashcodeStr << winId; 123 hashcodeStr << ":"; 124 hashcodeStr << accessId; 125 return hashcodeStr.str(); 126 } 127 WrapperElement(Widget & widget)128 void ElementNodeIteratorImpl::WrapperElement(Widget &widget) 129 { 130 AccessibilityElementInfo element = elementInfoLists_[currentIndex_]; 131 WrapperNodeAttrToVec(widget, element); 132 } 133 VisitNodeByChildAndBrother(Widget & widget)134 bool ElementNodeIteratorImpl::VisitNodeByChildAndBrother(Widget &widget) 135 { 136 int childCount = elementInfoLists_[currentIndex_].GetChildCount(); 137 if (childCount > 0) { 138 if (VisitChildren(widget)) { 139 return true; 140 } 141 } 142 143 if (elementToParentIndexMap_.find(currentIndex_) == elementToParentIndexMap_.cend()) { 144 LOG_D("This node has no parent: %{public}s", 145 std::to_string(elementInfoLists_[currentIndex_].GetAccessibilityId()).data()); 146 return false; 147 } 148 int parentIndex = elementToParentIndexMap_.at(currentIndex_); 149 int tempChildIndex = currentIndex_; 150 if (elementToParentIndexMap_.find(topIndex_) == elementToParentIndexMap_.cend()) { 151 LOG_D("This topIndex_ has no parent: %{public}d", topIndex_); 152 return false; 153 } 154 while (parentIndex != elementToParentIndexMap_.at(topIndex_)) { 155 if (VisitBrother(widget, parentIndex, tempChildIndex)) { 156 return true; 157 } 158 if (elementToParentIndexMap_.find(parentIndex) == elementToParentIndexMap_.cend()) { 159 LOG_D("This node has no parent: %{public}s", 160 std::to_string(elementInfoLists_[parentIndex].GetAccessibilityId()).data()); 161 return false; 162 } 163 tempChildIndex = parentIndex; 164 parentIndex = elementToParentIndexMap_.at(parentIndex); 165 } 166 return false; 167 } 168 VisitChildren(Widget & widget)169 bool ElementNodeIteratorImpl::VisitChildren(Widget& widget) 170 { 171 if (visitAndVisibleIndexSet_.find(currentIndex_) == visitAndVisibleIndexSet_.cend()) { 172 LOG_D("node %{public}s is invisible not find its children", 173 std::to_string(elementInfoLists_[currentIndex_].GetAccessibilityId()).data()); 174 return false; 175 } else { 176 for (size_t i = currentIndex_ + 1; i < elementInfoLists_.size(); ++i) { 177 if (elementInfoLists_[i].GetAccessibilityId() != elementInfoLists_[currentIndex_].GetChildId(0)) { 178 continue; 179 } 180 elementToParentIndexMap_.emplace(i, currentIndex_); 181 std::string parentHierarchy = elementIndexToHierarch_.at(currentIndex_); 182 currentIndex_ = i; 183 visitAndVisibleIndexSet_.insert(currentIndex_); 184 WrapperElement(widget); 185 widget.SetHierarchy(WidgetHierarchyBuilder::Build(parentHierarchy, 0)); 186 elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 187 return true; 188 } 189 return false; 190 } 191 } 192 VisitBrother(Widget & widget,int parentIndex,int tempChildIndex)193 bool ElementNodeIteratorImpl::VisitBrother(Widget &widget, int parentIndex, int tempChildIndex) 194 { 195 AccessibilityElementInfo &parentModel = elementInfoLists_[parentIndex]; 196 int parentChildCount = parentModel.GetChildCount(); 197 for (int i = 0; i < parentChildCount; ++i) { 198 if ((parentModel.GetChildId(i) == elementInfoLists_[tempChildIndex].GetAccessibilityId()) && 199 (i < parentChildCount - 1)) { 200 if (parentModel.GetChildId(i + 1) == elementInfoLists_[tempChildIndex + 1].GetAccessibilityId()) { 201 elementToParentIndexMap_.emplace(tempChildIndex + 1, parentIndex); 202 std::string parentHierarchy = elementIndexToHierarch_.at(parentIndex); 203 currentIndex_ = tempChildIndex + 1; 204 visitAndVisibleIndexSet_.insert(currentIndex_); 205 WrapperElement(widget); 206 widget.SetHierarchy(WidgetHierarchyBuilder::Build(parentHierarchy, i + 1)); 207 elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 208 return true; 209 } else { 210 LOG_E("Node error, except: %{public}s, actual is %{public}s", 211 std::to_string(parentModel.GetChildId(i + 1)).data(), 212 std::to_string(elementInfoLists_[tempChildIndex + 1].GetAccessibilityId()).data()); 213 } 214 } 215 } 216 return false; 217 } 218 WrapperNodeAttrToVec(Widget & widget,const AccessibilityElementInfo & element)219 void ElementNodeIteratorImpl::WrapperNodeAttrToVec(Widget &widget, const AccessibilityElementInfo &element) 220 { 221 Accessibility::Rect nodeOriginRect = elementInfoLists_[currentIndex_].GetRectInScreen(); 222 Rect visibleRect{nodeOriginRect.GetLeftTopXScreenPostion(), nodeOriginRect.GetRightBottomXScreenPostion(), 223 nodeOriginRect.GetLeftTopYScreenPostion(), nodeOriginRect.GetRightBottomYScreenPostion()}; 224 widget.SetBounds(visibleRect); 225 widget.SetAttr(UiAttr::ACCESSIBILITY_ID, std::to_string(element.GetAccessibilityId())); 226 widget.SetAttr(UiAttr::ID, element.GetInspectorKey()); 227 widget.SetAttr(UiAttr::TEXT, element.GetContent()); 228 widget.SetAttr(UiAttr::KEY, element.GetInspectorKey()); 229 widget.SetAttr(UiAttr::TYPE, element.GetComponentType()); 230 widget.SetAttr(UiAttr::DESCRIPTION, element.GetDescriptionInfo()); 231 if (element.GetComponentType() == "rootdecortag" || element.GetInspectorKey() == "ContainerModalTitleRow") { 232 widget.SetAttr(UiAttr::TYPE, "DecorBar"); 233 } 234 widget.SetAttr(UiAttr::ENABLED, element.IsEnabled() ? "true" : "false"); 235 widget.SetAttr(UiAttr::FOCUSED, element.IsFocused() ? "true" : "false"); 236 widget.SetAttr(UiAttr::SELECTED, element.IsSelected() ? "true" : "false"); 237 widget.SetAttr(UiAttr::CLICKABLE, "false"); 238 widget.SetAttr(UiAttr::LONG_CLICKABLE, "false"); 239 widget.SetAttr(UiAttr::SCROLLABLE, element.IsScrollable() ? "true" : "false"); 240 widget.SetAttr(UiAttr::CHECKABLE, element.IsCheckable() ? "true" : "false"); 241 widget.SetAttr(UiAttr::CHECKED, element.IsChecked() ? "true" : "false"); 242 widget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(element.GetWindowId())); 243 widget.SetAttr(UiAttr::ZINDEX, std::to_string(element.GetZIndex())); 244 widget.SetAttr(UiAttr::OPACITY, std::to_string(element.GetOpacity())); 245 widget.SetAttr(UiAttr::BACKGROUNDCOLOR, element.GetBackgroundColor()); 246 widget.SetAttr(UiAttr::BACKGROUNDIMAGE, element.GetBackgroundImage()); 247 widget.SetAttr(UiAttr::BLUR, element.GetBlur()); 248 widget.SetAttr(UiAttr::HITTESTBEHAVIOR, element.GetHitTestBehavior()); 249 widget.SetAttr(UiAttr::CLIP, element.GetClip() ? "true" : "false"); 250 stringstream boundStream; 251 boundStream << "[" << visibleRect.left_ << "," << visibleRect.top_ << "][" << visibleRect.right_ << "," 252 << visibleRect.bottom_ << "]"; 253 widget.SetAttr(UiAttr::ORIGBOUNDS, boundStream.str()); 254 widget.SetAttr(UiAttr::HASHCODE, ElementNodeIteratorImpl::GenerateNodeHashCode(element)); 255 if (!element.IsVisible()) { 256 LOG_D("widget %{public}s is not visible", widget.GetAttr(UiAttr::ACCESSIBILITY_ID).data()); 257 } 258 widget.SetAttr(UiAttr::VISIBLE, element.IsVisible() ? "true" : "false"); 259 const auto app = element.GetBundleName(); 260 widget.SetAttr(UiAttr::BUNDLENAME, app); 261 widget.SetAttr(UiAttr::HINT, element.GetHint()); 262 WrapperNodeActionAttrToVec(widget, element); 263 } 264 WrapperNodeActionAttrToVec(Widget & widget,const AccessibilityElementInfo & element)265 void ElementNodeIteratorImpl::WrapperNodeActionAttrToVec(Widget &widget, const AccessibilityElementInfo &element) 266 { 267 auto actions = element.GetActionList(); 268 for (auto &action : actions) { 269 switch (action.GetActionType()) { 270 case ACCESSIBILITY_ACTION_CLICK: 271 widget.SetAttr(UiAttr::CLICKABLE, "true"); 272 break; 273 case ACCESSIBILITY_ACTION_LONG_CLICK: 274 widget.SetAttr(UiAttr::LONG_CLICKABLE, "true"); 275 break; 276 default: 277 break; 278 } 279 } 280 } 281 } // namespace OHOS::uitest