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