• 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 "select_strategy.h"
17 namespace OHOS::uitest {
18     constexpr int32_t MAX_TRAVEL_TIMES = 20000;
RegisterAnchorMatch(const WidgetMatchModel & matchModel)19     void SelectStrategy::RegisterAnchorMatch(const WidgetMatchModel &matchModel)
20     {
21         anchorMatch_.emplace_back(matchModel);
22     }
23 
RegisterMyselfMatch(const WidgetMatchModel & matchModel)24     void SelectStrategy::RegisterMyselfMatch(const WidgetMatchModel &matchModel)
25     {
26         myselfMatch_.emplace_back(matchModel);
27     }
28 
SetWantMulti(bool isWantMulti)29     void SelectStrategy::SetWantMulti(bool isWantMulti)
30     {
31         wantMulti_ = isWantMulti;
32     }
33 
SetAndCalcSelectWindowRect(const Rect & windowBounds,const std::vector<Rect> & windowBoundsVec)34     void SelectStrategy::SetAndCalcSelectWindowRect(const Rect &windowBounds, const std::vector<Rect> &windowBoundsVec)
35     {
36         windowBounds_ = windowBounds;
37         overplayWindowBoundsVec_ = windowBoundsVec;
38     }
39 
~SelectStrategy()40     SelectStrategy::~SelectStrategy()
41     {
42         anchorMatch_.clear();
43         myselfMatch_.clear();
44     }
45 
CalcWidgetVisibleBounds(const Widget & widget,const Rect & containerParentRect,Rect & visibleRect)46     void SelectStrategy::CalcWidgetVisibleBounds(const Widget &widget,
47                                                  const Rect &containerParentRect,
48                                                  Rect &visibleRect)
49     {
50         // calc bounds with its window
51         Rect visibleInWindow{0, 0, 0, 0};
52         if (!RectAlgorithm::ComputeIntersection(widget.GetBounds(), windowBounds_, visibleInWindow)) {
53             LOG_D("Widget %{public}s bounds is %{public}s, without window bounds %{public}s, widget info is %{public}s",
54                   widget.GetAttr(UiAttr::ACCESSIBILITY_ID).data(), widget.GetBounds().Describe().data(),
55                   windowBounds_.Describe().data(), widget.ToStr().data());
56             visibleRect = Rect(0, 0, 0, 0);
57             return;
58         }
59         // calc bounds with its container parent
60         Rect visibleInParent{0, 0, 0, 0};
61         if (!RectAlgorithm::ComputeIntersection(visibleInWindow, containerParentRect, visibleInParent)) {
62             LOG_D("Widget %{public}s bounds is %{public}s, without parent bounds %{public}s, widget info is %{public}s",
63                   widget.GetAttr(UiAttr::ACCESSIBILITY_ID).data(), widget.GetBounds().Describe().data(),
64                   containerParentRect.Describe().data(), widget.ToStr().data());
65             visibleRect = Rect(0, 0, 0, 0);
66             return;
67         }
68         if (!RectAlgorithm::CheckEqual(containerParentRect, windowBounds_) ||
69             CONTAINER_TYPE.find(widget.GetAttr(UiAttr::TYPE)) != CONTAINER_TYPE.cend()) {
70             if (widget.IsVisible() && (visibleInParent.GetHeight() == 0 || visibleInParent.GetWidth() == 0)) {
71                 LOG_D("Widget %{public}s height or widget is zero, but it is container, keep it visible",
72                       widget.GetAttr(UiAttr::ACCESSIBILITY_ID).data());
73                 visibleRect = visibleInParent;
74                 return;
75             }
76         }
77         if (overplayWindowBoundsVec_.size() == 0) {
78             visibleRect = visibleInParent;
79             return;
80         }
81         // calc bounds with overplay windows
82         Rect visibleBounds{0, 0, 0, 0};
83         auto visible = RectAlgorithm::ComputeMaxVisibleRegion(visibleInParent, overplayWindowBoundsVec_, visibleBounds);
84         if (!visible) {
85             LOG_D("widget %{public}s is hide by overplays, widget info is %{public}s",
86                   widget.GetAttr(UiAttr::ACCESSIBILITY_ID).data(), widget.ToStr().data());
87             visibleRect = Rect{0, 0, 0, 0};
88         } else {
89             visibleRect = visibleBounds;
90         }
91     }
92 
Describe() const93     std::string SelectStrategy::Describe() const
94     {
95         std::string strategy = "PLAIN";
96         switch (GetStrategyType()) {
97             case StrategyEnum::PLAIN:
98                 strategy = "PLAIN";
99                 break;
100             case StrategyEnum::WITH_IN:
101                 strategy = "WITH_IN";
102                 break;
103             case StrategyEnum::IS_AFTER:
104                 strategy = "IS_AFTER";
105                 break;
106             case StrategyEnum::IS_BEFORE:
107                 strategy = "IS_BEFORE";
108                 break;
109             case StrategyEnum::COMPLEX:
110                 strategy = "COMPLEX";
111                 break;
112             default:
113                 LOG_I("Error StrategyType, use plain");
114                 strategy = "PLAIN";
115                 break;
116         }
117         stringstream ss;
118         ss << "{";
119         ss << strategy;
120         if (!anchorMatch_.empty()) {
121             ss << "; anchorMatcher=";
122             for (auto &locator : anchorMatch_) {
123                 ss << "[" << locator.Describe() << "]";
124             }
125         }
126         if (!myselfMatch_.empty()) {
127             ss << "; myselfMatcher=";
128             for (auto &locator : myselfMatch_) {
129                 ss << "[" << locator.Describe() << "]";
130             }
131         }
132         ss << "}";
133         return ss.str();
134     }
135 
RefreshWidgetBounds(const Rect & containerParentRect,Widget & widget)136     void SelectStrategy::RefreshWidgetBounds(const Rect &containerParentRect, Widget &widget)
137     {
138         Rect oriBounds = widget.GetBounds();
139         // parent rect is 0, but it has child, keep visible from access not refresh bound
140         if ((oriBounds.GetHeight() == 0 || oriBounds.GetWidth() == 0) &&
141             (oriBounds.left_ >= 0 && oriBounds.top_ >= 0)) {
142             LOG_D("Widget %{public}s height or widget is zero, rect is %{public}s, keep it visible",
143                   widget.GetAttr(UiAttr::ACCESSIBILITY_ID).data(), oriBounds.Describe().data());
144             return;
145         }
146         Rect widgetVisibleBounds = Rect{0, 0, 0, 0};
147         CalcWidgetVisibleBounds(widget, containerParentRect, widgetVisibleBounds);
148 
149         widget.SetBounds(widgetVisibleBounds);
150         if (widgetVisibleBounds.GetHeight() <= 0 && widgetVisibleBounds.GetWidth() <= 0) {
151             widget.SetAttr(UiAttr::VISIBLE, "false");
152             return;
153         }
154         if (widget.GetAttr(UiAttr::VISIBLE) == "false") {
155             return;
156         }
157         if (widgetVisibleBounds.GetHeight() <= 0 || widgetVisibleBounds.GetWidth() <= 0) {
158             if (!RectAlgorithm::CheckEqual(containerParentRect, windowBounds_) ||
159                 CONTAINER_TYPE.find(widget.GetAttr(UiAttr::TYPE)) != CONTAINER_TYPE.cend()) {
160                 widget.SetAttr(UiAttr::VISIBLE, "true");
161             } else {
162                 widget.SetAttr(UiAttr::VISIBLE, "false");
163             }
164         } else {
165             widget.SetAttr(UiAttr::VISIBLE, "true");
166         }
167     }
168 
169     class AfterSelectorStrategy : public SelectStrategy {
170     public:
171         AfterSelectorStrategy() = default;
LocateNode(const Window & window,ElementNodeIterator & elementNodeRef,std::vector<Widget> & visitWidgets,std::vector<int> & targetWidgets,bool isRemoveInvisible=true)172         void LocateNode(const Window &window,
173                         ElementNodeIterator &elementNodeRef,
174                         std::vector<Widget> &visitWidgets,
175                         std::vector<int> &targetWidgets,
176                         bool isRemoveInvisible = true) override
177         {
178             elementNodeRef.ClearDFSNext();
179             SetAndCalcSelectWindowRect(window.bounds_, window.invisibleBoundsVec_);
180             while (true) {
181                 Widget anchorWidget{"test"};
182                 if (!elementNodeRef.DFSNext(anchorWidget, window.id_)) {
183                     return;
184                 }
185                 anchorWidget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(window.id_));
186                 Rect anchorParentInWindow = windowBounds_;
187                 elementNodeRef.GetParentContainerBounds(anchorParentInWindow);
188                 RefreshWidgetBounds(anchorParentInWindow, anchorWidget);
189                 if (anchorWidget.GetAttr(UiAttr::VISIBLE) == "false") {
190                     elementNodeRef.RemoveInvisibleWidget();
191                     LOG_D("Widget %{public}s is invisible", anchorWidget.GetAttr(UiAttr::ACCESSIBILITY_ID).data());
192                     continue;
193                 }
194                 visitWidgets.emplace_back(move(anchorWidget));
195                 if (visitWidgets.size() > MAX_TRAVEL_TIMES) {
196                     LOG_E("ElementInfos obtained from AAMS is abnormal, traversal node failed");
197                     visitWidgets.clear();
198                     return;
199                 }
200                 std::reference_wrapper<Widget const> tempAnchorWidget = visitWidgets.back();
201                 elementNodeRef.CheckAndUpdateContainerRectMap();
202                 bool isAnchorMatch = true;
203                 for (const auto &anchorIt : anchorMatch_) {
204                     isAnchorMatch = tempAnchorWidget.get().MatchAttr(anchorIt) && isAnchorMatch;
205                     if (!isAnchorMatch) {
206                         break;
207                     }
208                 }
209                 if (!isAnchorMatch) {
210                     continue;
211                 }
212                 LocateNodeAfterAnchor(window, elementNodeRef, visitWidgets, targetWidgets);
213             }
214         }
215 
LocateNodeAfterAnchor(const Window & window,ElementNodeIterator & elementNodeRef,std::vector<Widget> & visitWidgets,std::vector<int> & targetWidgets)216         void LocateNodeAfterAnchor(const Window &window,
217                                    ElementNodeIterator &elementNodeRef,
218                                    std::vector<Widget> &visitWidgets,
219                                    std::vector<int> &targetWidgets)
220         {
221             while (true) {
222                 Widget myselfWidget{"myselfWidget"};
223                 if (!elementNodeRef.DFSNext(myselfWidget, window.id_)) {
224                     return;
225                 }
226                 myselfWidget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(window.id_));
227                 Rect parentInWindow = windowBounds_;
228                 elementNodeRef.GetParentContainerBounds(parentInWindow);
229                 RefreshWidgetBounds(parentInWindow, myselfWidget);
230                 if (myselfWidget.GetAttr(UiAttr::VISIBLE) == "false") {
231                     elementNodeRef.RemoveInvisibleWidget();
232                     LOG_D("Widget %{public}s is invisible", myselfWidget.GetAttr(UiAttr::ACCESSIBILITY_ID).data());
233                     continue;
234                 }
235                 visitWidgets.emplace_back(move(myselfWidget));
236                 if (visitWidgets.size() > MAX_TRAVEL_TIMES) {
237                     LOG_E("ElementInfos obtained from AAMS is abnormal, traversal node failed");
238                     visitWidgets.clear();
239                     return;
240                 }
241                 std::reference_wrapper<Widget const> tempWidget = visitWidgets.back();
242                 elementNodeRef.CheckAndUpdateContainerRectMap();
243                 bool isMyselfMatch = true;
244                 for (const auto &myselfIt : myselfMatch_) {
245                     isMyselfMatch = tempWidget.get().MatchAttr(myselfIt) && isMyselfMatch;
246                     if (!isMyselfMatch) {
247                         break;
248                     }
249                 }
250                 if (!isMyselfMatch) {
251                     continue;
252                 }
253                 targetWidgets.emplace_back(visitWidgets.size() - 1);
254                 if (!wantMulti_) {
255                     return;
256                 }
257             }
258         }
259 
GetStrategyType() const260         StrategyEnum GetStrategyType() const override
261         {
262             return StrategyEnum::IS_AFTER;
263         }
264         ~AfterSelectorStrategy() override = default;
265     };
266 
267     class BeforeSelectorStrategy : public SelectStrategy {
268     public:
269         BeforeSelectorStrategy() = default;
LocateNode(const Window & window,ElementNodeIterator & elementNodeRef,std::vector<Widget> & visitWidgets,std::vector<int> & targetWidgets,bool isRemoveInvisible=true)270         void LocateNode(const Window &window,
271                         ElementNodeIterator &elementNodeRef,
272                         std::vector<Widget> &visitWidgets,
273                         std::vector<int> &targetWidgets,
274                         bool isRemoveInvisible = true) override
275         {
276             elementNodeRef.ClearDFSNext();
277             SetAndCalcSelectWindowRect(window.bounds_, window.invisibleBoundsVec_);
278             while (true) {
279                 Widget anchorWidget{"anchorWidget"};
280                 if (!elementNodeRef.DFSNext(anchorWidget, window.id_)) {
281                     return;
282                 }
283                 anchorWidget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(window.id_));
284                 Rect parentInWindow = windowBounds_;
285                 elementNodeRef.GetParentContainerBounds(parentInWindow);
286                 RefreshWidgetBounds(parentInWindow, anchorWidget);
287                 if (anchorWidget.GetAttr(UiAttr::VISIBLE) == "false") {
288                     elementNodeRef.RemoveInvisibleWidget();
289                     LOG_D("Widget %{public}s is invisible", anchorWidget.GetAttr(UiAttr::ACCESSIBILITY_ID).data());
290                     continue;
291                 }
292                 visitWidgets.emplace_back(move(anchorWidget));
293                 if (visitWidgets.size() > MAX_TRAVEL_TIMES) {
294                     LOG_E("ElementInfos obtained from AAMS is abnormal, traversal node failed");
295                     visitWidgets.clear();
296                     return;
297                 }
298                 std::reference_wrapper<Widget const> tempAnchorWidget = visitWidgets.back();
299                 elementNodeRef.CheckAndUpdateContainerRectMap();
300                 bool isAnchorMatch = true;
301                 for (const auto &anchorIt : anchorMatch_) {
302                     isAnchorMatch = tempAnchorWidget.get().MatchAttr(anchorIt) && isAnchorMatch;
303                     if (!isAnchorMatch) {
304                         break;
305                     }
306                 }
307                 if (!isAnchorMatch) {
308                     continue;
309                 }
310                 LocateNodeAfterBeforeAnchor(visitWidgets, targetWidgets);
311                 if (!targetWidgets.empty() && !wantMulti_) {
312                     return;
313                 }
314             }
315         }
316 
LocateNodeAfterBeforeAnchor(std::vector<Widget> & visitWidgets,std::vector<int> & targetWidgets)317         void LocateNodeAfterBeforeAnchor(std::vector<Widget> &visitWidgets,
318                                          std::vector<int> &targetWidgets)
319         {
320             size_t index = 0;
321             if (targetWidgets.size() > 0) {
322                 index = targetWidgets[targetWidgets.size() - 1] + 1;
323             }
324             for (; index < visitWidgets.size() - 1; ++index) {
325                 bool isMyselfMatch = true;
326                 for (const auto &myselfIt : myselfMatch_) {
327                     isMyselfMatch = visitWidgets[index].MatchAttr(myselfIt) && isMyselfMatch;
328                 }
329                 if (!isMyselfMatch) {
330                     continue;
331                 }
332                 targetWidgets.emplace_back(index);
333                 if (!wantMulti_) {
334                     return;
335                 }
336             }
337         }
338 
GetStrategyType() const339         StrategyEnum GetStrategyType() const override
340         {
341             return StrategyEnum::IS_BEFORE;
342         }
343         ~BeforeSelectorStrategy() override = default;
344     };
345 
346     class WithInSelectorStrategy : public SelectStrategy {
347     public:
348         WithInSelectorStrategy() = default;
LocateNode(const Window & window,ElementNodeIterator & elementNodeRef,std::vector<Widget> & visitWidgets,std::vector<int> & targetWidgets,bool isRemoveInvisible=true)349         void LocateNode(const Window &window,
350                         ElementNodeIterator &elementNodeRef,
351                         std::vector<Widget> &visitWidgets,
352                         std::vector<int> &targetWidgets,
353                         bool isRemoveInvisible = true) override
354         {
355             elementNodeRef.ClearDFSNext();
356             SetAndCalcSelectWindowRect(window.bounds_, window.invisibleBoundsVec_);
357             while (true) {
358                 Widget anchorWidget{"withInWidget"};
359                 if (!elementNodeRef.DFSNext(anchorWidget, window.id_)) {
360                     return;
361                 }
362                 anchorWidget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(window.id_));
363                 Rect anchorParentInWindow = windowBounds_;
364                 elementNodeRef.GetParentContainerBounds(anchorParentInWindow);
365                 RefreshWidgetBounds(anchorParentInWindow, anchorWidget);
366                 if (anchorWidget.GetAttr(UiAttr::VISIBLE) == "false") {
367                     elementNodeRef.RemoveInvisibleWidget();
368                     LOG_D("Widget %{public}s is invisible", anchorWidget.GetAttr(UiAttr::ACCESSIBILITY_ID).data());
369                     continue;
370                 }
371                 visitWidgets.emplace_back(move(anchorWidget));
372                 if (visitWidgets.size() > MAX_TRAVEL_TIMES) {
373                     LOG_E("ElementInfos obtained from AAMS is abnormal, traversal node failed");
374                     visitWidgets.clear();
375                     return;
376                 }
377                 std::reference_wrapper<Widget const> tempAnchorWidget = visitWidgets.back();
378                 elementNodeRef.CheckAndUpdateContainerRectMap();
379                 bool isAnchorMatch = true;
380                 for (const auto &anchorIt : anchorMatch_) {
381                     isAnchorMatch = tempAnchorWidget.get().MatchAttr(anchorIt) && isAnchorMatch;
382                     if (!isAnchorMatch) {
383                         break;
384                     }
385                 }
386                 if (!isAnchorMatch) {
387                     continue;
388                 }
389                 LocateNodeWithInAnchor(window, elementNodeRef, visitWidgets, targetWidgets);
390                 if (!targetWidgets.empty() && !wantMulti_) {
391                     return;
392                 }
393             }
394         }
395 
LocateNodeWithInAnchor(const Window & window,ElementNodeIterator & elementNodeRef,std::vector<Widget> & visitWidgets,std::vector<int> & targetWidgets)396         void LocateNodeWithInAnchor(const Window &window,
397                                     ElementNodeIterator &elementNodeRef,
398                                     std::vector<Widget> &visitWidgets,
399                                     std::vector<int> &targetWidgets)
400         {
401             // restore current index and set top to anchor index
402             elementNodeRef.RestoreNodeIndexByAnchor();
403             while (true) {
404                 Widget myselfWidget{"myselfWidget"};
405                 if (!elementNodeRef.DFSNextWithInTarget(myselfWidget)) {
406                     break;
407                 }
408                 myselfWidget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(window.id_));
409                 Rect parentInWindow = windowBounds_;
410                 elementNodeRef.GetParentContainerBounds(parentInWindow);
411                 RefreshWidgetBounds(parentInWindow, myselfWidget);
412 
413                 if (myselfWidget.GetAttr(UiAttr::VISIBLE) == "false") {
414                     elementNodeRef.RemoveInvisibleWidget();
415                     LOG_D("Widget %{public}s is invisible", myselfWidget.GetAttr(UiAttr::ACCESSIBILITY_ID).data());
416                     continue;
417                 }
418                 visitWidgets.emplace_back(move(myselfWidget));
419                 if (visitWidgets.size() > MAX_TRAVEL_TIMES) {
420                     LOG_E("ElementInfos obtained from AAMS is abnormal, traversal node failed");
421                     visitWidgets.clear();
422                     return;
423                 }
424                 std::reference_wrapper<Widget const> tempWidget = visitWidgets.back();
425                 elementNodeRef.CheckAndUpdateContainerRectMap();
426                 bool isMyselfMatch = true;
427                 for (const auto &myselfIt : myselfMatch_) {
428                     isMyselfMatch = tempWidget.get().MatchAttr(myselfIt) && isMyselfMatch;
429                     if (!isMyselfMatch) {
430                         break;
431                     }
432                 }
433                 if (!isMyselfMatch) {
434                     continue;
435                 }
436                 targetWidgets.emplace_back(visitWidgets.size() - 1);
437                 if (!wantMulti_) {
438                     return;
439                 }
440             }
441             elementNodeRef.ResetNodeIndexToAnchor();
442         }
443 
GetStrategyType() const444         StrategyEnum GetStrategyType() const override
445         {
446             return StrategyEnum::WITH_IN;
447         }
448         ~WithInSelectorStrategy() override = default;
449     };
450 
451     class PlainSelectorStrategy : public SelectStrategy {
452     public:
453         PlainSelectorStrategy() = default;
LocateNode(const Window & window,ElementNodeIterator & elementNodeRef,std::vector<Widget> & visitWidgets,std::vector<int> & targetWidgets,bool isRemoveInvisible=true)454         void LocateNode(const Window &window,
455                         ElementNodeIterator &elementNodeRef,
456                         std::vector<Widget> &visitWidgets,
457                         std::vector<int> &targetWidgets,
458                         bool isRemoveInvisible = true) override
459         {
460             elementNodeRef.ClearDFSNext();
461             SetAndCalcSelectWindowRect(window.bounds_, window.invisibleBoundsVec_);
462             while (true) {
463                 Widget myselfWidget{"myselfWidget"};
464                 if (!elementNodeRef.DFSNext(myselfWidget, window.id_)) {
465                     return;
466                 }
467                 myselfWidget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(window.id_));
468                 if (isRemoveInvisible) {
469                     Rect parentInWindow = windowBounds_;
470                     elementNodeRef.GetParentContainerBounds(parentInWindow);
471                     RefreshWidgetBounds(parentInWindow, myselfWidget);
472                     if (myselfWidget.GetAttr(UiAttr::VISIBLE) == "false") {
473                         elementNodeRef.RemoveInvisibleWidget();
474                         continue;
475                     }
476                 }
477                 visitWidgets.emplace_back(move(myselfWidget));
478                 if (visitWidgets.size() > MAX_TRAVEL_TIMES) {
479                     LOG_E("ElementInfos obtained from AAMS is abnormal, traversal node failed");
480                     visitWidgets.clear();
481                     return;
482                 }
483                 std::reference_wrapper<Widget const> tempWidget = visitWidgets.back();
484                 elementNodeRef.CheckAndUpdateContainerRectMap();
485                 bool isMyselfMatch = true;
486                 for (const auto &myselfIt : myselfMatch_) {
487                     isMyselfMatch = tempWidget.get().MatchAttr(myselfIt) && isMyselfMatch;
488                     if (!isMyselfMatch) {
489                         break;
490                     }
491                 }
492                 if (!isMyselfMatch) {
493                     continue;
494                 }
495                 targetWidgets.emplace_back(visitWidgets.size() - 1);
496                 if (!wantMulti_) {
497                     return;
498                 }
499             }
500             //
501         }
502 
GetStrategyType() const503         StrategyEnum GetStrategyType() const override
504         {
505             return StrategyEnum::PLAIN;
506         }
507         ~PlainSelectorStrategy() override = default;
508     };
509 
510     class ComplexSelectorStrategy : public SelectStrategy {
511     public:
512         ComplexSelectorStrategy() = default;
LocateNode(const Window & window,ElementNodeIterator & elementNodeRef,std::vector<Widget> & visitWidgets,std::vector<int> & targetWidgets,bool isRemoveInvisible=true)513         void LocateNode(const Window &window,
514                         ElementNodeIterator &elementNodeRef,
515                         std::vector<Widget> &visitWidgets,
516                         std::vector<int> &targetWidgets,
517                         bool isRemoveInvisible = true) override
518         {
519             elementNodeRef.ClearDFSNext();
520             SetAndCalcSelectWindowRect(window.bounds_, window.invisibleBoundsVec_);
521             std::vector<int> fakeTargetWidgets;
522             while (true) {
523                 Widget myselfWidget{"myselfWidget"};
524                 if (!elementNodeRef.DFSNext(myselfWidget, window.id_)) {
525                     break;
526                 }
527                 myselfWidget.SetAttr(UiAttr::HOST_WINDOW_ID, std::to_string(window.id_));
528 
529                 Rect parentInWindow = windowBounds_;
530                 elementNodeRef.GetParentContainerBounds(parentInWindow);
531                 RefreshWidgetBounds(parentInWindow, myselfWidget);
532                 if (myselfWidget.GetAttr(UiAttr::VISIBLE) == "false") {
533                     elementNodeRef.RemoveInvisibleWidget();
534                     continue;
535                 }
536 
537                 visitWidgets.emplace_back(move(myselfWidget));
538                 if (visitWidgets.size() > MAX_TRAVEL_TIMES) {
539                     LOG_E("ElementInfos obtained from AAMS is abnormal, traversal node failed");
540                     visitWidgets.clear();
541                     return;
542                 }
543                 std::reference_wrapper<Widget const> tempWidget = visitWidgets.back();
544                 elementNodeRef.CheckAndUpdateContainerRectMap();
545                 bool isMyselfMatch = true;
546                 for (const auto &myselfIt : myselfMatch_) {
547                     isMyselfMatch = tempWidget.get().MatchAttr(myselfIt) && isMyselfMatch;
548                     if (!isMyselfMatch) {
549                         break;
550                     }
551                 }
552                 if (!isMyselfMatch) {
553                     continue;
554                 }
555                 fakeTargetWidgets.emplace_back(visitWidgets.size() - 1);
556             }
557             DoComplexSelect(visitWidgets, fakeTargetWidgets, targetWidgets);
558         }
559 
RegisterMultiAfterAnchor(const std::vector<WidgetMatchModel> & afterAnchor)560         void RegisterMultiAfterAnchor(const std::vector<WidgetMatchModel> &afterAnchor)
561         {
562             multiAfterAnchorMatcher.emplace_back(afterAnchor);
563         }
564 
RegisterMultiBeforeAnchor(const std::vector<WidgetMatchModel> & beforeAnchor)565         void RegisterMultiBeforeAnchor(const std::vector<WidgetMatchModel> &beforeAnchor)
566         {
567             multiBeforeAnchorMatcher.emplace_back(beforeAnchor);
568         }
569 
RegisterMultiWithInAnchor(const std::vector<WidgetMatchModel> & withInAnchor)570         void RegisterMultiWithInAnchor(const std::vector<WidgetMatchModel> &withInAnchor)
571         {
572             multiWithInAnchorMatcher.emplace_back(withInAnchor);
573         }
574 
CalcMaxAfterAnchorIndex(const std::vector<Widget> & visitWidgets)575         int CalcMaxAfterAnchorIndex(const std::vector<Widget> &visitWidgets)
576         {
577             int32_t startAfterIndex = -1;
578             for (auto &afterLocator : multiAfterAnchorMatcher) {
579                 int32_t startIndex = 0;
580                 for (; static_cast<size_t>(startIndex) < visitWidgets.size(); ++startIndex) {
581                     bool isFrontMatch = true;
582                     for (auto &attrModel : afterLocator) {
583                         isFrontMatch = isFrontMatch && visitWidgets[startIndex].MatchAttr(attrModel);
584                     }
585                     if (isFrontMatch) {
586                         startAfterIndex = startAfterIndex > startIndex ? startAfterIndex : startIndex;
587                         break;
588                     }
589                 }
590                 if (static_cast<size_t>(startIndex) == visitWidgets.size()) {
591                     startAfterIndex = visitWidgets.size();
592                 }
593             }
594             return startAfterIndex;
595         }
596 
CalcMinBeforeAnchorIndex(const std::vector<Widget> & visitWidgets)597         int CalcMinBeforeAnchorIndex(const std::vector<Widget> &visitWidgets)
598         {
599             int startBeforeIndex = visitWidgets.size();
600             for (auto &beforeLocator : multiBeforeAnchorMatcher) {
601                 int beforeIndex = visitWidgets.size() - 1;
602                 for (; beforeIndex > 0; --beforeIndex) {
603                     bool isRearMatch = true;
604                     for (auto &attrModel : beforeLocator) {
605                         isRearMatch = isRearMatch && visitWidgets[beforeIndex].MatchAttr(attrModel);
606                     }
607                     if (isRearMatch) {
608                         startBeforeIndex = startBeforeIndex > beforeIndex ? beforeIndex : startBeforeIndex;
609                         break;
610                     }
611                 }
612                 if (beforeIndex == 0) {
613                     startBeforeIndex = 0;
614                 }
615             }
616             return startBeforeIndex;
617         }
618 
CheckTargetIdByParentSelect(const std::vector<int> & parentIndexVec,const std::vector<Widget> & visitWidgets)619         bool CheckTargetIdByParentSelect(const std::vector<int> &parentIndexVec,
620                                          const std::vector<Widget> &visitWidgets)
621         {
622             bool isAllLocatorMatch = true;
623             for (auto &parentLocator : multiWithInAnchorMatcher) {
624                 bool hasValidParent = false;
625                 for (auto &parentIndex : parentIndexVec) {
626                     bool isMatch = true;
627                     for (auto &selfMatch : parentLocator) {
628                         isMatch = isMatch && visitWidgets[parentIndex].MatchAttr(selfMatch);
629                     }
630                     hasValidParent = hasValidParent || isMatch;
631                     if (hasValidParent) {
632                         break;
633                     }
634                 }
635                 isAllLocatorMatch = isAllLocatorMatch && hasValidParent;
636                 if (!isAllLocatorMatch) {
637                     break;
638                 }
639             }
640             return isAllLocatorMatch;
641         }
642 
LocateNodeWithInComplexSelect(std::vector<int> & filterParentValidId,const std::vector<Widget> & visitWidgets,const std::vector<int> & myselfTargets)643         void LocateNodeWithInComplexSelect(std::vector<int> &filterParentValidId,
644                                            const std::vector<Widget> &visitWidgets,
645                                            const std::vector<int> &myselfTargets)
646         {
647             for (int targetId : myselfTargets) {
648                 const std::string &targetHie = visitWidgets[targetId].GetHierarchy();
649                 std::vector<int> parentIndexVec;
650                 for (size_t index = 0; index < visitWidgets.size(); ++index) {
651                     const std::string &visitHie = visitWidgets[index].GetHierarchy();
652                     if (targetHie.length() <= visitHie.length() || targetHie.find(visitHie) != 0) {
653                         continue;
654                     }
655                     parentIndexVec.emplace_back(index);
656                 }
657                 bool isAllLocatorMatch = CheckTargetIdByParentSelect(parentIndexVec, visitWidgets);
658                 if (isAllLocatorMatch) {
659                     filterParentValidId.emplace_back(targetId);
660                 }
661             }
662         }
663 
DoComplexSelect(const std::vector<Widget> & visitWidgets,std::vector<int> & fakeTargets,std::vector<int> & myselfTargets)664         void DoComplexSelect(const std::vector<Widget> &visitWidgets,
665                              std::vector<int> &fakeTargets,
666                              std::vector<int> &myselfTargets)
667         {
668             int startAfterIndex = CalcMaxAfterAnchorIndex(visitWidgets);
669             int startBeforeIndex = CalcMinBeforeAnchorIndex(visitWidgets);
670             if (startBeforeIndex <= startAfterIndex) {
671                 return;
672             }
673             for (auto index : fakeTargets) {
674                 if (index > startAfterIndex && index < startBeforeIndex) {
675                     myselfTargets.emplace_back(index);
676                 }
677             }
678 
679             if (myselfTargets.empty()) {
680                 return;
681             }
682             if (multiWithInAnchorMatcher.empty()) {
683                 if (!wantMulti_) {
684                     myselfTargets.erase(myselfTargets.begin() + 1, myselfTargets.end());
685                 }
686                 return;
687             }
688             std::vector<int> filterParentValidId;
689             LocateNodeWithInComplexSelect(filterParentValidId, visitWidgets, myselfTargets);
690             if (filterParentValidId.empty()) {
691                 myselfTargets.clear();
692                 return;
693             }
694             if (wantMulti_) {
695                 myselfTargets = filterParentValidId;
696             } else {
697                 myselfTargets.clear();
698                 myselfTargets.emplace_back(filterParentValidId.at(0));
699             }
700         }
701 
GetStrategyType() const702         StrategyEnum GetStrategyType() const override
703         {
704             return StrategyEnum::COMPLEX;
705         }
706         ~ComplexSelectorStrategy() override = default;
707 
708     private:
709         std::vector<std::vector<WidgetMatchModel>> multiAfterAnchorMatcher;
710         std::vector<std::vector<WidgetMatchModel>> multiBeforeAnchorMatcher;
711         std::vector<std::vector<WidgetMatchModel>> multiWithInAnchorMatcher;
712     };
713 
BuildComplexStrategy(const StrategyBuildParam & buildParam,bool isWantMulti)714     static std::unique_ptr<SelectStrategy> BuildComplexStrategy(const StrategyBuildParam &buildParam, bool isWantMulti)
715     {
716         std::unique_ptr<ComplexSelectorStrategy> selectStrategy = std::make_unique<ComplexSelectorStrategy>();
717         for (const auto &matchModel : buildParam.myselfMatcher) {
718             selectStrategy->RegisterMyselfMatch(matchModel);
719         }
720         for (const auto &afterWidgetAnchor : buildParam.afterAnchorMatcherVec) {
721             selectStrategy->RegisterMultiAfterAnchor(afterWidgetAnchor);
722         }
723         for (const auto &beforeWidgetAnchor : buildParam.beforeAnchorMatcherVec) {
724             selectStrategy->RegisterMultiBeforeAnchor(beforeWidgetAnchor);
725         }
726         for (const auto &withInWidgetAnchor : buildParam.withInAnchorMatcherVec) {
727             selectStrategy->RegisterMultiWithInAnchor(withInWidgetAnchor);
728         }
729         selectStrategy->SetWantMulti(isWantMulti);
730         return selectStrategy;
731     }
732 
BuildWithInStrategy(const StrategyBuildParam & buildParam,bool isWantMulti)733     static std::unique_ptr<SelectStrategy> BuildWithInStrategy(const StrategyBuildParam &buildParam, bool isWantMulti)
734     {
735         std::unique_ptr<SelectStrategy> selectStrategy = std::make_unique<WithInSelectorStrategy>();
736         for (const auto &matchModel : buildParam.myselfMatcher) {
737             selectStrategy->RegisterMyselfMatch(matchModel);
738         }
739         for (const auto &anchorModel : buildParam.withInAnchorMatcherVec.at(0)) {
740             selectStrategy->RegisterAnchorMatch(anchorModel);
741         }
742         selectStrategy->SetWantMulti(isWantMulti);
743         return selectStrategy;
744     }
745 
BuildBeforeStrategy(const StrategyBuildParam & buildParam,bool isWantMulti)746     static std::unique_ptr<SelectStrategy> BuildBeforeStrategy(const StrategyBuildParam &buildParam, bool isWantMulti)
747     {
748         std::unique_ptr<SelectStrategy> selectStrategy = std::make_unique<BeforeSelectorStrategy>();
749         for (const auto &matchModel : buildParam.myselfMatcher) {
750             selectStrategy->RegisterMyselfMatch(matchModel);
751         }
752         for (const auto &anchorModel : buildParam.beforeAnchorMatcherVec.at(0)) {
753             selectStrategy->RegisterAnchorMatch(anchorModel);
754         }
755         selectStrategy->SetWantMulti(isWantMulti);
756         return selectStrategy;
757     }
758 
BuildAfterStrategy(const StrategyBuildParam & buildParam,bool isWantMulti)759     static std::unique_ptr<SelectStrategy> BuildAfterStrategy(const StrategyBuildParam &buildParam, bool isWantMulti)
760     {
761         std::unique_ptr<SelectStrategy> selectStrategy = std::make_unique<AfterSelectorStrategy>();
762         for (const auto &matchModel : buildParam.myselfMatcher) {
763             selectStrategy->RegisterMyselfMatch(matchModel);
764         }
765         for (const auto &anchorModel : buildParam.afterAnchorMatcherVec.at(0)) {
766             selectStrategy->RegisterAnchorMatch(anchorModel);
767         }
768         selectStrategy->SetWantMulti(isWantMulti);
769         return selectStrategy;
770     }
771 
BuildSelectStrategy(const StrategyBuildParam & buildParam,bool isWantMulti)772     std::unique_ptr<SelectStrategy> SelectStrategy::BuildSelectStrategy(const StrategyBuildParam &buildParam,
773                                                                         bool isWantMulti)
774     {
775         if (buildParam.afterAnchorMatcherVec.empty() && buildParam.beforeAnchorMatcherVec.empty() &&
776             buildParam.withInAnchorMatcherVec.empty()) {
777             std::unique_ptr<SelectStrategy> selectStrategy = std::make_unique<PlainSelectorStrategy>();
778             for (const auto &matchModel : buildParam.myselfMatcher) {
779                 selectStrategy->RegisterMyselfMatch(matchModel);
780             }
781             selectStrategy->SetWantMulti(isWantMulti);
782             return selectStrategy;
783         } else if (!buildParam.afterAnchorMatcherVec.empty() && (buildParam.afterAnchorMatcherVec.size() == 1) &&
784                    buildParam.beforeAnchorMatcherVec.empty() && buildParam.withInAnchorMatcherVec.empty()) {
785             return BuildAfterStrategy(buildParam, isWantMulti);
786         } else if (buildParam.afterAnchorMatcherVec.empty() && !buildParam.beforeAnchorMatcherVec.empty() &&
787                    (buildParam.beforeAnchorMatcherVec.size() == 1) && buildParam.withInAnchorMatcherVec.empty()) {
788             return BuildBeforeStrategy(buildParam, isWantMulti);
789         } else if (buildParam.afterAnchorMatcherVec.empty() && buildParam.beforeAnchorMatcherVec.empty() &&
790                    !buildParam.withInAnchorMatcherVec.empty() && (buildParam.withInAnchorMatcherVec.size() == 1)) {
791             return BuildWithInStrategy(buildParam, isWantMulti);
792         } else {
793             return BuildComplexStrategy(buildParam, isWantMulti);
794         }
795     }
796 } // namespace OHOS::uitest