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