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