1886da342Sopenharmony_ci/* 2886da342Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3886da342Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4886da342Sopenharmony_ci * you may not use this file except in compliance with the License. 5886da342Sopenharmony_ci * You may obtain a copy of the License at 6886da342Sopenharmony_ci * 7886da342Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8886da342Sopenharmony_ci * 9886da342Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10886da342Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11886da342Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12886da342Sopenharmony_ci * See the License for the specific language governing permissions and 13886da342Sopenharmony_ci * limitations under the License. 14886da342Sopenharmony_ci */ 15886da342Sopenharmony_ci 16886da342Sopenharmony_ci#include "element_node_iterator_impl.h" 17886da342Sopenharmony_cinamespace OHOS::uitest { 18886da342Sopenharmony_ci using namespace OHOS::Accessibility; 19886da342Sopenharmony_ci 20886da342Sopenharmony_ci ElementNodeIteratorImpl::ElementNodeIteratorImpl( 21886da342Sopenharmony_ci const std::vector<AccessibilityElementInfo> &elements) 22886da342Sopenharmony_ci { 23886da342Sopenharmony_ci elementInfoLists_ = std::move(elements); 24886da342Sopenharmony_ci currentIndex_ = -1; 25886da342Sopenharmony_ci topIndex_ = 0; 26886da342Sopenharmony_ci lastCurrentIndex_ = -1; 27886da342Sopenharmony_ci } 28886da342Sopenharmony_ci 29886da342Sopenharmony_ci ElementNodeIteratorImpl::ElementNodeIteratorImpl() 30886da342Sopenharmony_ci { 31886da342Sopenharmony_ci currentIndex_ = -1; 32886da342Sopenharmony_ci topIndex_ = 0; 33886da342Sopenharmony_ci lastCurrentIndex_ = -1; 34886da342Sopenharmony_ci } 35886da342Sopenharmony_ci 36886da342Sopenharmony_ci ElementNodeIteratorImpl::~ElementNodeIteratorImpl() 37886da342Sopenharmony_ci { 38886da342Sopenharmony_ci elementInfoLists_.clear(); 39886da342Sopenharmony_ci elementToParentIndexMap_.clear(); 40886da342Sopenharmony_ci elementIndexToHierarch_.clear(); 41886da342Sopenharmony_ci visitAndVisibleIndexSet_.clear(); 42886da342Sopenharmony_ci } 43886da342Sopenharmony_ci 44886da342Sopenharmony_ci bool ElementNodeIteratorImpl::DFSNextWithInTarget(Widget &widget) 45886da342Sopenharmony_ci { 46886da342Sopenharmony_ci if (currentIndex_ == topIndex_) { 47886da342Sopenharmony_ci int count = elementInfoLists_[currentIndex_].GetChildCount(); 48886da342Sopenharmony_ci if (count <= 0) { 49886da342Sopenharmony_ci return false; 50886da342Sopenharmony_ci } 51886da342Sopenharmony_ci for (size_t i = currentIndex_ + 1; i < elementInfoLists_.size(); ++i) { 52886da342Sopenharmony_ci if (elementInfoLists_[i].GetAccessibilityId() != elementInfoLists_[currentIndex_].GetChildId(0)) { 53886da342Sopenharmony_ci continue; 54886da342Sopenharmony_ci } 55886da342Sopenharmony_ci elementToParentIndexMap_.emplace(i, currentIndex_); 56886da342Sopenharmony_ci std::string parentHierarchy = elementIndexToHierarch_.at(currentIndex_); 57886da342Sopenharmony_ci currentIndex_ = i; 58886da342Sopenharmony_ci visitAndVisibleIndexSet_.insert(currentIndex_); 59886da342Sopenharmony_ci WrapperElement(widget); 60886da342Sopenharmony_ci widget.SetHierarchy(WidgetHierarchyBuilder::Build(parentHierarchy, 0)); 61886da342Sopenharmony_ci elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 62886da342Sopenharmony_ci return true; 63886da342Sopenharmony_ci } 64886da342Sopenharmony_ci } 65886da342Sopenharmony_ci return VisitNodeByChildAndBrother(widget); 66886da342Sopenharmony_ci } 67886da342Sopenharmony_ci 68886da342Sopenharmony_ci bool ElementNodeIteratorImpl::DFSNext(Widget &widget, uint32_t windowId) 69886da342Sopenharmony_ci { 70886da342Sopenharmony_ci if (IsVisitFinish()) { 71886da342Sopenharmony_ci return false; 72886da342Sopenharmony_ci } 73886da342Sopenharmony_ci 74886da342Sopenharmony_ci if (currentIndex_ == -1) { 75886da342Sopenharmony_ci currentIndex_ = 0; 76886da342Sopenharmony_ci elementToParentIndexMap_.emplace(currentIndex_, -1); 77886da342Sopenharmony_ci visitAndVisibleIndexSet_.insert(currentIndex_); 78886da342Sopenharmony_ci WrapperElement(widget); 79886da342Sopenharmony_ci widget.SetHierarchy(ROOT_HIERARCHY + to_string(windowId)); 80886da342Sopenharmony_ci elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 81886da342Sopenharmony_ci return true; 82886da342Sopenharmony_ci } 83886da342Sopenharmony_ci return VisitNodeByChildAndBrother(widget); 84886da342Sopenharmony_ci } 85886da342Sopenharmony_ci 86886da342Sopenharmony_ci bool ElementNodeIteratorImpl::IsVisitFinish() const 87886da342Sopenharmony_ci { 88886da342Sopenharmony_ci return elementInfoLists_.size() == elementToParentIndexMap_.size(); 89886da342Sopenharmony_ci } 90886da342Sopenharmony_ci 91886da342Sopenharmony_ci void ElementNodeIteratorImpl::RestoreNodeIndexByAnchor() 92886da342Sopenharmony_ci { 93886da342Sopenharmony_ci topIndex_ = currentIndex_; 94886da342Sopenharmony_ci lastCurrentIndex_ = currentIndex_; 95886da342Sopenharmony_ci LOG_D("select in widget, store current index is %{public}d", currentIndex_); 96886da342Sopenharmony_ci } 97886da342Sopenharmony_ci 98886da342Sopenharmony_ci void ElementNodeIteratorImpl::ResetNodeIndexToAnchor() 99886da342Sopenharmony_ci { 100886da342Sopenharmony_ci topIndex_ = 0; 101886da342Sopenharmony_ci } 102886da342Sopenharmony_ci 103886da342Sopenharmony_ci void ElementNodeIteratorImpl::ClearDFSNext() 104886da342Sopenharmony_ci { 105886da342Sopenharmony_ci elementToParentIndexMap_.clear(); 106886da342Sopenharmony_ci elementIndexToHierarch_.clear(); 107886da342Sopenharmony_ci visitAndVisibleIndexSet_.clear(); 108886da342Sopenharmony_ci currentIndex_ = -1; 109886da342Sopenharmony_ci topIndex_ = 0; 110886da342Sopenharmony_ci } 111886da342Sopenharmony_ci 112886da342Sopenharmony_ci void ElementNodeIteratorImpl::RemoveInvisibleWidget() 113886da342Sopenharmony_ci { 114886da342Sopenharmony_ci visitAndVisibleIndexSet_.erase(currentIndex_); 115886da342Sopenharmony_ci } 116886da342Sopenharmony_ci 117886da342Sopenharmony_ci std::string ElementNodeIteratorImpl::GetTextByKey(const std::string key) 118886da342Sopenharmony_ci { 119886da342Sopenharmony_ci for (auto element : elementInfoLists_) { 120886da342Sopenharmony_ci if (element.GetInspectorKey() == key) { 121886da342Sopenharmony_ci return element.GetContent(); 122886da342Sopenharmony_ci } 123886da342Sopenharmony_ci } 124886da342Sopenharmony_ci return ""; 125886da342Sopenharmony_ci } 126886da342Sopenharmony_ci 127886da342Sopenharmony_ci std::string ElementNodeIteratorImpl::GenerateNodeHashCode(const AccessibilityElementInfo &element) 128886da342Sopenharmony_ci { 129886da342Sopenharmony_ci int32_t winId = element.GetWindowId(); 130886da342Sopenharmony_ci int64_t accessId = element.GetAccessibilityId(); 131886da342Sopenharmony_ci std::stringstream hashcodeStr; 132886da342Sopenharmony_ci hashcodeStr << winId; 133886da342Sopenharmony_ci hashcodeStr << ":"; 134886da342Sopenharmony_ci hashcodeStr << accessId; 135886da342Sopenharmony_ci return hashcodeStr.str(); 136886da342Sopenharmony_ci } 137886da342Sopenharmony_ci 138886da342Sopenharmony_ci void ElementNodeIteratorImpl::WrapperElement(Widget &widget) 139886da342Sopenharmony_ci { 140886da342Sopenharmony_ci AccessibilityElementInfo element = elementInfoLists_[currentIndex_]; 141886da342Sopenharmony_ci WrapperNodeAttrToVec(widget, element); 142886da342Sopenharmony_ci } 143886da342Sopenharmony_ci 144886da342Sopenharmony_ci bool ElementNodeIteratorImpl::VisitNodeByChildAndBrother(Widget &widget) 145886da342Sopenharmony_ci { 146886da342Sopenharmony_ci int childCount = elementInfoLists_[currentIndex_].GetChildCount(); 147886da342Sopenharmony_ci if (childCount > 0) { 148886da342Sopenharmony_ci if (VisitChildren(widget)) { 149886da342Sopenharmony_ci return true; 150886da342Sopenharmony_ci } 151886da342Sopenharmony_ci } 152886da342Sopenharmony_ci 153886da342Sopenharmony_ci if (elementToParentIndexMap_.find(currentIndex_) == elementToParentIndexMap_.cend()) { 154886da342Sopenharmony_ci LOG_D("This node has no parent: %{public}s", 155886da342Sopenharmony_ci std::to_string(elementInfoLists_[currentIndex_].GetAccessibilityId()).data()); 156886da342Sopenharmony_ci return false; 157886da342Sopenharmony_ci } 158886da342Sopenharmony_ci int parentIndex = elementToParentIndexMap_.at(currentIndex_); 159886da342Sopenharmony_ci int tempChildIndex = currentIndex_; 160886da342Sopenharmony_ci if (elementToParentIndexMap_.find(topIndex_) == elementToParentIndexMap_.cend()) { 161886da342Sopenharmony_ci LOG_D("This topIndex_ has no parent: %{public}d", topIndex_); 162886da342Sopenharmony_ci return false; 163886da342Sopenharmony_ci } 164886da342Sopenharmony_ci while (parentIndex != elementToParentIndexMap_.at(topIndex_)) { 165886da342Sopenharmony_ci if (VisitBrother(widget, parentIndex, tempChildIndex)) { 166886da342Sopenharmony_ci return true; 167886da342Sopenharmony_ci } 168886da342Sopenharmony_ci if (elementToParentIndexMap_.find(parentIndex) == elementToParentIndexMap_.cend()) { 169886da342Sopenharmony_ci LOG_D("This node has no parent: %{public}s", 170886da342Sopenharmony_ci std::to_string(elementInfoLists_[parentIndex].GetAccessibilityId()).data()); 171886da342Sopenharmony_ci return false; 172886da342Sopenharmony_ci } 173886da342Sopenharmony_ci tempChildIndex = parentIndex; 174886da342Sopenharmony_ci parentIndex = elementToParentIndexMap_.at(parentIndex); 175886da342Sopenharmony_ci } 176886da342Sopenharmony_ci return false; 177886da342Sopenharmony_ci } 178886da342Sopenharmony_ci 179886da342Sopenharmony_ci bool ElementNodeIteratorImpl::VisitChildren(Widget& widget) 180886da342Sopenharmony_ci { 181886da342Sopenharmony_ci if (visitAndVisibleIndexSet_.find(currentIndex_) == visitAndVisibleIndexSet_.cend()) { 182886da342Sopenharmony_ci LOG_D("node %{public}s is invisible not find its children", 183886da342Sopenharmony_ci std::to_string(elementInfoLists_[currentIndex_].GetAccessibilityId()).data()); 184886da342Sopenharmony_ci return false; 185886da342Sopenharmony_ci } else { 186886da342Sopenharmony_ci for (size_t i = currentIndex_ + 1; i < elementInfoLists_.size(); ++i) { 187886da342Sopenharmony_ci if (elementInfoLists_[i].GetAccessibilityId() != elementInfoLists_[currentIndex_].GetChildId(0)) { 188886da342Sopenharmony_ci continue; 189886da342Sopenharmony_ci } 190886da342Sopenharmony_ci elementToParentIndexMap_.emplace(i, currentIndex_); 191886da342Sopenharmony_ci std::string parentHierarchy = elementIndexToHierarch_.at(currentIndex_); 192886da342Sopenharmony_ci currentIndex_ = i; 193886da342Sopenharmony_ci visitAndVisibleIndexSet_.insert(currentIndex_); 194886da342Sopenharmony_ci WrapperElement(widget); 195886da342Sopenharmony_ci widget.SetHierarchy(WidgetHierarchyBuilder::Build(parentHierarchy, 0)); 196886da342Sopenharmony_ci elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 197886da342Sopenharmony_ci return true; 198886da342Sopenharmony_ci } 199886da342Sopenharmony_ci return false; 200886da342Sopenharmony_ci } 201886da342Sopenharmony_ci } 202886da342Sopenharmony_ci 203886da342Sopenharmony_ci bool ElementNodeIteratorImpl::VisitBrother(Widget &widget, int parentIndex, int tempChildIndex) 204886da342Sopenharmony_ci { 205886da342Sopenharmony_ci AccessibilityElementInfo &parentModel = elementInfoLists_[parentIndex]; 206886da342Sopenharmony_ci int parentChildCount = parentModel.GetChildCount(); 207886da342Sopenharmony_ci for (int i = 0; i < parentChildCount; ++i) { 208886da342Sopenharmony_ci if ((parentModel.GetChildId(i) == elementInfoLists_[tempChildIndex].GetAccessibilityId()) && 209886da342Sopenharmony_ci (i < parentChildCount - 1)) { 210886da342Sopenharmony_ci if (parentModel.GetChildId(i + 1) == elementInfoLists_[tempChildIndex + 1].GetAccessibilityId()) { 211886da342Sopenharmony_ci elementToParentIndexMap_.emplace(tempChildIndex + 1, parentIndex); 212886da342Sopenharmony_ci std::string parentHierarchy = elementIndexToHierarch_.at(parentIndex); 213886da342Sopenharmony_ci currentIndex_ = tempChildIndex + 1; 214886da342Sopenharmony_ci visitAndVisibleIndexSet_.insert(currentIndex_); 215886da342Sopenharmony_ci WrapperElement(widget); 216886da342Sopenharmony_ci widget.SetHierarchy(WidgetHierarchyBuilder::Build(parentHierarchy, i + 1)); 217886da342Sopenharmony_ci elementIndexToHierarch_.emplace(currentIndex_, widget.GetHierarchy()); 218886da342Sopenharmony_ci return true; 219886da342Sopenharmony_ci } else { 220886da342Sopenharmony_ci LOG_E("Node error, except: %{public}s, actual is %{public}s", 221886da342Sopenharmony_ci std::to_string(parentModel.GetChildId(i + 1)).data(), 222886da342Sopenharmony_ci std::to_string(elementInfoLists_[tempChildIndex + 1].GetAccessibilityId()).data()); 223886da342Sopenharmony_ci } 224886da342Sopenharmony_ci } 225886da342Sopenharmony_ci } 226886da342Sopenharmony_ci return false; 227886da342Sopenharmony_ci } 228886da342Sopenharmony_ci 229886da342Sopenharmony_ci void ElementNodeIteratorImpl::WrapperNodeAttrToVec(Widget &widget, const AccessibilityElementInfo &element) 230886da342Sopenharmony_ci { 231886da342Sopenharmony_ci Accessibility::Rect nodeOriginRect = elementInfoLists_[currentIndex_].GetRectInScreen(); 232886da342Sopenharmony_ci Rect visibleRect{nodeOriginRect.GetLeftTopXScreenPostion(), nodeOriginRect.GetRightBottomXScreenPostion(), 233886da342Sopenharmony_ci nodeOriginRect.GetLeftTopYScreenPostion(), nodeOriginRect.GetRightBottomYScreenPostion()}; 234886da342Sopenharmony_ci widget.SetBounds(visibleRect); 235886da342Sopenharmony_ci widget.SetAttr(UiAttr::ACCESSIBILITY_ID, std::to_string(element.GetAccessibilityId())); 236886da342Sopenharmony_ci widget.SetAttr(UiAttr::ID, element.GetInspectorKey()); 237886da342Sopenharmony_ci widget.SetAttr(UiAttr::TEXT, element.GetContent()); 238886da342Sopenharmony_ci widget.SetAttr(UiAttr::KEY, element.GetInspectorKey()); 239886da342Sopenharmony_ci widget.SetAttr(UiAttr::TYPE, element.GetComponentType()); 240886da342Sopenharmony_ci widget.SetAttr(UiAttr::DESCRIPTION, element.GetDescriptionInfo()); 241886da342Sopenharmony_ci if (element.GetComponentType() == "rootdecortag" || element.GetInspectorKey() == "ContainerModalTitleRow") { 242886da342Sopenharmony_ci widget.SetAttr(UiAttr::TYPE, "DecorBar"); 243886da342Sopenharmony_ci } 244886da342Sopenharmony_ci widget.SetAttr(UiAttr::ENABLED, element.IsEnabled() ? "true" : "false"); 245886da342Sopenharmony_ci widget.SetAttr(UiAttr::FOCUSED, element.IsFocused() ? "true" : "false"); 246886da342Sopenharmony_ci widget.SetAttr(UiAttr::SELECTED, element.IsSelected() ? "true" : "false"); 247886da342Sopenharmony_ci widget.SetAttr(UiAttr::CLICKABLE, "false"); 248886da342Sopenharmony_ci widget.SetAttr(UiAttr::LONG_CLICKABLE, "false"); 249886da342Sopenharmony_ci widget.SetAttr(UiAttr::SCROLLABLE, element.IsScrollable() ? "true" : "false"); 250886da342Sopenharmony_ci widget.SetAttr(UiAttr::CHECKABLE, element.IsCheckable() ? "true" : "false"); 251886da342Sopenharmony_ci widget.SetAttr(UiAttr::CHECKED, element.IsChecked() ? "true" : "false"); 252886da342Sopenharmony_ci widget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(element.GetWindowId())); 253886da342Sopenharmony_ci widget.SetAttr(UiAttr::ZINDEX, std::to_string(element.GetZIndex())); 254886da342Sopenharmony_ci widget.SetAttr(UiAttr::OPACITY, std::to_string(element.GetOpacity())); 255886da342Sopenharmony_ci widget.SetAttr(UiAttr::BACKGROUNDCOLOR, element.GetBackgroundColor()); 256886da342Sopenharmony_ci widget.SetAttr(UiAttr::BACKGROUNDIMAGE, element.GetBackgroundImage()); 257886da342Sopenharmony_ci widget.SetAttr(UiAttr::BLUR, element.GetBlur()); 258886da342Sopenharmony_ci widget.SetAttr(UiAttr::HITTESTBEHAVIOR, element.GetHitTestBehavior()); 259886da342Sopenharmony_ci widget.SetAttr(UiAttr::CLIP, element.GetClip() ? "true" : "false"); 260886da342Sopenharmony_ci stringstream boundStream; 261886da342Sopenharmony_ci boundStream << "[" << visibleRect.left_ << "," << visibleRect.top_ << "][" << visibleRect.right_ << "," 262886da342Sopenharmony_ci << visibleRect.bottom_ << "]"; 263886da342Sopenharmony_ci widget.SetAttr(UiAttr::ORIGBOUNDS, boundStream.str()); 264886da342Sopenharmony_ci widget.SetAttr(UiAttr::HASHCODE, ElementNodeIteratorImpl::GenerateNodeHashCode(element)); 265886da342Sopenharmony_ci if (!element.IsVisible()) { 266886da342Sopenharmony_ci LOG_D("widget %{public}s is not visible", widget.GetAttr(UiAttr::ACCESSIBILITY_ID).data()); 267886da342Sopenharmony_ci } 268886da342Sopenharmony_ci widget.SetAttr(UiAttr::VISIBLE, element.IsVisible() ? "true" : "false"); 269886da342Sopenharmony_ci const auto app = element.GetBundleName(); 270886da342Sopenharmony_ci widget.SetAttr(UiAttr::BUNDLENAME, app); 271886da342Sopenharmony_ci widget.SetAttr(UiAttr::HINT, element.GetHint()); 272886da342Sopenharmony_ci WrapperNodeActionAttrToVec(widget, element); 273886da342Sopenharmony_ci } 274886da342Sopenharmony_ci 275886da342Sopenharmony_ci void ElementNodeIteratorImpl::WrapperNodeActionAttrToVec(Widget &widget, const AccessibilityElementInfo &element) 276886da342Sopenharmony_ci { 277886da342Sopenharmony_ci auto actions = element.GetActionList(); 278886da342Sopenharmony_ci for (auto &action : actions) { 279886da342Sopenharmony_ci switch (action.GetActionType()) { 280886da342Sopenharmony_ci case ACCESSIBILITY_ACTION_CLICK: 281886da342Sopenharmony_ci widget.SetAttr(UiAttr::CLICKABLE, "true"); 282886da342Sopenharmony_ci break; 283886da342Sopenharmony_ci case ACCESSIBILITY_ACTION_LONG_CLICK: 284886da342Sopenharmony_ci widget.SetAttr(UiAttr::LONG_CLICKABLE, "true"); 285886da342Sopenharmony_ci break; 286886da342Sopenharmony_ci default: 287886da342Sopenharmony_ci break; 288886da342Sopenharmony_ci } 289886da342Sopenharmony_ci } 290886da342Sopenharmony_ci } 291886da342Sopenharmony_ci} // namespace OHOS::uitest