• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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