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