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