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