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