1 /* 2 * Copyright (c) 2021-2022 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 <future> 17 #include "ui_model.h" 18 #include "ui_driver.h" 19 20 namespace OHOS::uitest { 21 using namespace std; 22 using namespace nlohmann; 23 24 class WindowCacheCompareGreater { 25 public: operator ()(const WindowCacheModel & w1,const WindowCacheModel & w2)26 bool operator()(const WindowCacheModel &w1, const WindowCacheModel &w2) 27 { 28 if (w1.window_.actived_) { 29 return true; 30 } 31 if (w2.window_.actived_) { 32 return false; 33 } 34 if (w1.window_.focused_) { 35 return true; 36 } 37 if (w2.window_.focused_) { 38 return false; 39 } 40 return w1.window_.windowLayer_ > w2.window_.windowLayer_; 41 } 42 }; 43 44 std::unique_ptr<UiController> UiDriver::uiController_; 45 RegisterController(std::unique_ptr<UiController> controller)46 void UiDriver::RegisterController(std::unique_ptr<UiController> controller) 47 { 48 uiController_ = move(controller); 49 } 50 RegisterUiEventListener(std::shared_ptr<UiEventListener> listener)51 void UiDriver::RegisterUiEventListener(std::shared_ptr<UiEventListener> listener) 52 { 53 uiController_->RegisterUiEventListener(listener); 54 } 55 CheckStatus(bool isConnected,ApiCallErr & error)56 bool UiDriver::CheckStatus(bool isConnected, ApiCallErr &error) 57 { 58 DCHECK(uiController_); 59 if (isConnected && !uiController_->IsWorkable()) { 60 LOG_W("Not connect to AAMS, try to reconnect"); 61 if (!uiController_->Initialize(error)) { 62 LOG_E("%{public}s", error.message_.c_str()); 63 return false; 64 } 65 } 66 return true; 67 } 68 UpdateUIWindows(ApiCallErr & error,int32_t targetDisplay)69 void UiDriver::UpdateUIWindows(ApiCallErr &error, int32_t targetDisplay) 70 { 71 visitWidgets_.clear(); 72 targetWidgetsIndex_.clear(); 73 displayToWindowCacheMap_.clear(); 74 if (!CheckStatus(true, error)) { 75 return; 76 } 77 std::map<int32_t, vector<Window>> currentDisplayAndWindowCacheMap; 78 uiController_->GetUiWindows(currentDisplayAndWindowCacheMap, targetDisplay); 79 if (currentDisplayAndWindowCacheMap.empty()) { 80 LOG_E("Get Windows Failed"); 81 error = ApiCallErr(ERR_INTERNAL, "Get window nodes failed"); 82 } 83 for (auto dm : currentDisplayAndWindowCacheMap) { 84 auto currentWindowVec = dm.second; 85 std::vector<WindowCacheModel> windowCacheVec; 86 for (const auto &win : currentWindowVec) { 87 WindowCacheModel cacheModel(win); 88 windowCacheVec.emplace_back(std::move(cacheModel)); 89 std::stringstream ss; 90 ss << "window rect is "; 91 ss << win.bounds_.Describe(); 92 ss << "overplay window rects are:["; 93 for (const auto& overRect : win.invisibleBoundsVec_) { 94 ss << overRect.Describe(); 95 ss << ", "; 96 } 97 ss << "]"; 98 LOG_D("window: %{public}d in display %{public}d, %{public}s", 99 win.id_, win.displayId_, ss.str().data()); 100 } 101 // actice or focus window move to top 102 std::sort(windowCacheVec.begin(), windowCacheVec.end(), WindowCacheCompareGreater()); 103 displayToWindowCacheMap_.insert(make_pair(dm.first, move(windowCacheVec))); 104 } 105 } 106 DumpWindowsInfo(const DumpOption & option,Rect & mergeBounds,nlohmann::json & childDom)107 void UiDriver::DumpWindowsInfo(const DumpOption &option, Rect& mergeBounds, nlohmann::json& childDom) 108 { 109 std::vector<WidgetMatchModel> emptyMatcher; 110 StrategyBuildParam buildParam; 111 buildParam.myselfMatcher = emptyMatcher; 112 std::unique_ptr<SelectStrategy> selectStrategy = SelectStrategy::BuildSelectStrategy(buildParam, true); 113 auto dm = displayToWindowCacheMap_.find(option.displayId_); 114 if (dm == displayToWindowCacheMap_.end()) { 115 return; 116 } 117 auto &windowCacheVec = dm->second; 118 for (auto &winCache : windowCacheVec) { 119 if (option.bundleName_ != "" && winCache.window_.bundleName_ != option.bundleName_) { 120 LOG_D("skip window(%{public}s), it is not target window %{public}s", 121 winCache.window_.bundleName_.data(), option.bundleName_.data()); 122 continue; 123 } 124 if (option.windowId_ != "" && winCache.window_.id_ != atoi(option.windowId_.c_str())) { 125 LOG_D("skip window(%{public}d), it is not target window %{public}s", 126 winCache.window_.id_, option.windowId_.data()); 127 continue; 128 } 129 visitWidgets_.clear(); 130 targetWidgetsIndex_.clear(); 131 if (!uiController_->GetWidgetsInWindow(winCache.window_, winCache.widgetIterator_, mode_)) { 132 LOG_W("Get Widget from window[%{public}d] failed, skip the window", winCache.window_.id_); 133 continue; 134 } 135 selectStrategy->LocateNode(winCache.window_, *winCache.widgetIterator_, visitWidgets_, targetWidgetsIndex_, 136 option); 137 nlohmann::json child = nlohmann::json(); 138 if (visitWidgets_.empty()) { 139 LOG_E("Window %{public}s has no node, skip it", winCache.window_.bundleName_.data()); 140 continue; 141 } else { 142 DumpHandler::DumpWindowInfoToJson(visitWidgets_, child); 143 } 144 child["attributes"]["abilityName"] = winCache.window_.abilityName_; 145 child["attributes"]["bundleName"] = winCache.window_.bundleName_; 146 child["attributes"]["pagePath"] = winCache.window_.pagePath_; 147 childDom.emplace_back(child); 148 mergeBounds.left_ = std::min(mergeBounds.left_, winCache.window_.bounds_.left_); 149 mergeBounds.top_ = std::min(mergeBounds.top_, winCache.window_.bounds_.top_); 150 mergeBounds.right_ = std::max(mergeBounds.right_, winCache.window_.bounds_.right_); 151 mergeBounds.bottom_ = std::max(mergeBounds.bottom_, winCache.window_.bounds_.bottom_); 152 } 153 } 154 DumpUiHierarchy(nlohmann::json & out,const DumpOption & option,ApiCallErr & error)155 void UiDriver::DumpUiHierarchy(nlohmann::json &out, const DumpOption &option, ApiCallErr &error) 156 { 157 UpdateUIWindows(error, option.displayId_); 158 if (error.code_ != NO_ERROR) { 159 return; 160 } 161 auto dm = displayToWindowCacheMap_.find(option.displayId_); 162 if (dm == displayToWindowCacheMap_.end()) { 163 LOG_E("Get windows id display %{public}d failed, dump error.", option.displayId_); 164 error = ApiCallErr(ERR_INTERNAL, "Get window nodes failed"); 165 return; 166 } 167 nlohmann::json childDom = nlohmann::json::array(); 168 Rect mergeBounds{0, 0, 0, 0}; 169 DumpWindowsInfo(option, mergeBounds, childDom); 170 if (option.listWindows_) { 171 out = childDom; 172 } else { 173 nlohmann::json attrData = nlohmann::json(); 174 175 for (int i = 0; i < UiAttr::HIERARCHY; ++i) { 176 attrData[ATTR_NAMES[i].data()] = ""; 177 } 178 std::stringstream ss; 179 ss << "[" << mergeBounds.left_ << "," << mergeBounds.top_ << "]" 180 << "[" << mergeBounds.right_ << "," << mergeBounds.bottom_ << "]"; 181 attrData[ATTR_NAMES[UiAttr::BOUNDS].data()] = ss.str(); 182 out["attributes"] = attrData; 183 out["children"] = childDom; 184 } 185 186 if (option.addExternAttr_) { 187 map<int32_t, string_view> elementTrees; 188 vector<char *> buffers; 189 auto &windowCacheVec = dm->second; 190 for (auto &winCache : windowCacheVec) { 191 char *buffer = nullptr; 192 size_t len = 0; 193 uiController_->GetHidumperInfo(to_string(winCache.window_.id_), &buffer, len); 194 if (buffer == nullptr) { 195 continue; 196 } 197 elementTrees.insert(make_pair(winCache.window_.id_, string_view(buffer, len))); 198 buffers.push_back(buffer); 199 } 200 DumpHandler::AddExtraAttrs(out, elementTrees, 0); 201 for (auto &buf : buffers) { 202 delete buf; 203 } 204 } 205 } 206 CloneFreeWidget(const Widget & from,const string & selectDesc)207 static unique_ptr<Widget> CloneFreeWidget(const Widget &from, const string &selectDesc) 208 { 209 auto clone = from.Clone(from.GetHierarchy()); 210 clone->SetAttr(UiAttr::DUMMY_ATTRNAME_SELECTION, selectDesc + from.GetAttr(UiAttr::HASHCODE)); 211 // save the selection desc as dummy attribute 212 return clone; 213 } 214 ConstructSelectStrategyByRetrieve(const Widget & widget)215 static std::unique_ptr<SelectStrategy> ConstructSelectStrategyByRetrieve(const Widget &widget) 216 { 217 WidgetMatchModel attrMatch{UiAttr::HASHCODE, widget.GetAttr(UiAttr::HASHCODE), EQ}; 218 StrategyBuildParam buildParam; 219 buildParam.myselfMatcher.emplace_back(attrMatch); 220 return SelectStrategy::BuildSelectStrategy(buildParam, false); 221 } 222 GetHostApp(const Widget & widget)223 string UiDriver::GetHostApp(const Widget &widget) 224 { 225 auto winId = widget.GetAttr(UiAttr::HOST_WINDOW_ID); 226 auto displayId = widget.GetDisplayId(); 227 if (winId.length() < 1) { 228 winId = "0"; 229 } 230 auto dm = displayToWindowCacheMap_.find(displayId); 231 if (dm == displayToWindowCacheMap_.end()) { 232 return ""; 233 } 234 auto &windowCacheVec = dm->second; 235 auto id = atoi(winId.c_str()); 236 for (auto &windowCache : windowCacheVec) { 237 if (id == windowCache.window_.id_) { 238 // If not a actived window, get all. 239 if (windowCache.window_.actived_ == false) { 240 return ""; 241 } 242 return windowCache.window_.bundleName_; 243 } 244 } 245 return ""; 246 } 247 RetrieveWidget(const Widget & widget,ApiCallErr & err,bool updateUi)248 const Widget *UiDriver::RetrieveWidget(const Widget &widget, ApiCallErr &err, bool updateUi) 249 { 250 if (updateUi) { 251 UpdateUIWindows(err, widget.GetDisplayId()); 252 if (err.code_ != NO_ERROR) { 253 LOG_E("Retrieve Widget with error %{public}s", err.message_.c_str()); 254 return nullptr; 255 } 256 } else { 257 visitWidgets_.clear(); 258 targetWidgetsIndex_.clear(); 259 } 260 std::unique_ptr<SelectStrategy> selectStrategy = ConstructSelectStrategyByRetrieve(widget); 261 auto &windowCacheVec = displayToWindowCacheMap_.find(widget.GetDisplayId())->second; 262 for (auto &curWinCache : windowCacheVec) { 263 if (widget.GetAttr(UiAttr::HOST_WINDOW_ID) != std::to_string(curWinCache.window_.id_)) { 264 continue; 265 } 266 selectStrategy->SetAndCalcSelectWindowRect(curWinCache.window_.bounds_, 267 curWinCache.window_.invisibleBoundsVec_); 268 if (curWinCache.widgetIterator_ == nullptr) { 269 if (!uiController_->GetWidgetsInWindow(curWinCache.window_, curWinCache.widgetIterator_, mode_)) { 270 LOG_W("Get Widget from window[%{public}d] failed, skip the window", curWinCache.window_.id_); 271 continue; 272 } 273 } 274 DumpOption option; 275 selectStrategy->LocateNode(curWinCache.window_, *curWinCache.widgetIterator_, visitWidgets_, 276 targetWidgetsIndex_, option); 277 if (!targetWidgetsIndex_.empty()) { 278 break; 279 } 280 } 281 stringstream msg; 282 msg << "Widget: " << widget.GetAttr(UiAttr::DUMMY_ATTRNAME_SELECTION); 283 msg << "dose not exist on current UI! Check if the UI has changed after you got the widget object"; 284 if (targetWidgetsIndex_.empty()) { 285 msg << "(NoCandidates)"; 286 err = ApiCallErr(ERR_COMPONENT_LOST, msg.str()); 287 LOG_W("%{public}s", err.message_.c_str()); 288 return nullptr; 289 } 290 DCHECK(targetWidgetsIndex_.size() == 1); 291 // confirm type 292 if (widget.GetAttr(UiAttr::TYPE) != visitWidgets_[targetWidgetsIndex_[0]].GetAttr(UiAttr::TYPE)) { 293 msg << " (CompareEqualsFailed)"; 294 err = ApiCallErr(ERR_COMPONENT_LOST, msg.str()); 295 LOG_W("%{public}s", err.message_.c_str()); 296 return nullptr; 297 } 298 return &visitWidgets_[targetWidgetsIndex_[0]]; 299 } 300 TriggerKey(const KeyAction & key,const UiOpArgs & opt,ApiCallErr & error,int32_t displayId)301 void UiDriver::TriggerKey(const KeyAction &key, const UiOpArgs &opt, ApiCallErr &error, int32_t displayId) 302 { 303 if (!CheckStatus(false, error)) { 304 return; 305 } 306 if (!CheckDisplayExist(displayId)) { 307 error = ApiCallErr(ERR_INVALID_INPUT, "Invalid display id."); 308 return; 309 } 310 vector<KeyEvent> events; 311 key.ComputeEvents(events, opt); 312 if (events.empty()) { 313 return; 314 } 315 uiController_->InjectKeyEventSequence(events, displayId); 316 } 317 FindWidgets(const WidgetSelector & selector,vector<unique_ptr<Widget>> & rev,ApiCallErr & err,bool updateUi)318 void UiDriver::FindWidgets(const WidgetSelector &selector, vector<unique_ptr<Widget>> &rev, 319 ApiCallErr &err, bool updateUi) 320 { 321 UiOpArgs opt; 322 uiController_->WaitForUiSteady(opt.uiSteadyThresholdMs_, opt.waitUiSteadyMaxMs_); 323 if (updateUi) { 324 UpdateUIWindows(err, selector.GetDisplayLocator()); 325 if (err.code_ != NO_ERROR) { 326 return; 327 } 328 } else { 329 visitWidgets_.clear(); 330 targetWidgetsIndex_.clear(); 331 } 332 auto appLocator = selector.GetAppLocator(); 333 for (auto &dm : displayToWindowCacheMap_) { 334 auto &windowCacheVec = dm.second; 335 for (auto &curWinCache : windowCacheVec) { 336 if (appLocator != "" && curWinCache.window_.bundleName_ != appLocator) { 337 continue; 338 } 339 if (curWinCache.widgetIterator_ == nullptr && 340 !uiController_->GetWidgetsInWindow(curWinCache.window_, curWinCache.widgetIterator_, mode_)) { 341 continue; 342 } 343 selector.Select(curWinCache.window_, *curWinCache.widgetIterator_, visitWidgets_, targetWidgetsIndex_); 344 if (!selector.IsWantMulti() && !targetWidgetsIndex_.empty()) { 345 break; 346 } 347 if (!selector.IsWantMulti()) { 348 visitWidgets_.clear(); 349 targetWidgetsIndex_.clear(); 350 } 351 } 352 if (!selector.IsWantMulti() && !targetWidgetsIndex_.empty()) { 353 break; 354 } 355 } 356 if (targetWidgetsIndex_.empty()) { 357 LOG_W("self node not found by %{public}s", selector.Describe().data()); 358 return; 359 } 360 // covert widgets to images as return value 361 uint32_t index = 0; 362 for (auto targetIndex : targetWidgetsIndex_) { 363 auto image = CloneFreeWidget(visitWidgets_[targetIndex], selector.Describe()); 364 // at sometime, more than one widgets are found, add the node index to the description 365 rev.emplace_back(move(image)); 366 index++; 367 } 368 } 369 WaitForWidget(const WidgetSelector & selector,const UiOpArgs & opt,ApiCallErr & err)370 unique_ptr<Widget> UiDriver::WaitForWidget(const WidgetSelector &selector, const UiOpArgs &opt, ApiCallErr &err) 371 { 372 const uint32_t sliceMs = 20; 373 const auto startMs = GetCurrentMillisecond(); 374 vector<unique_ptr<Widget>> receiver; 375 do { 376 FindWidgets(selector, receiver, err); 377 if (err.code_ != NO_ERROR) { // abort on error 378 return nullptr; 379 } 380 if (!receiver.empty()) { 381 return move(receiver.at(0)); 382 } 383 DelayMs(sliceMs); 384 } while (GetCurrentMillisecond() - startMs < opt.waitWidgetMaxMs_); 385 return nullptr; 386 } 387 DelayMs(uint32_t ms)388 void UiDriver::DelayMs(uint32_t ms) 389 { 390 if (ms > 0) { 391 this_thread::sleep_for(chrono::milliseconds(ms)); 392 } 393 } 394 PerformTouch(const TouchAction & touch,const UiOpArgs & opt,ApiCallErr & err)395 void UiDriver::PerformTouch(const TouchAction &touch, const UiOpArgs &opt, ApiCallErr &err) 396 { 397 if (!CheckStatus(false, err)) { 398 return; 399 } 400 PointerMatrix events; 401 touch.Decompose(events, opt); 402 if (events.Empty()) { 403 return; 404 } 405 auto displayId = events.At(0, 0).point_.displayId_; 406 if (!CheckDisplayExist(displayId)) { 407 LOG_E("No display: %{public}d", displayId); 408 err = ApiCallErr(ERR_INVALID_INPUT, "Invalid display id."); 409 return; 410 } 411 uiController_->InjectTouchEventSequence(events); 412 } 413 PerformMouseAction(const MouseAction & touch,const UiOpArgs & opt,ApiCallErr & err)414 void UiDriver::PerformMouseAction(const MouseAction &touch, const UiOpArgs &opt, ApiCallErr &err) 415 { 416 if (!CheckStatus(false, err)) { 417 return; 418 } 419 vector<MouseEvent> events; 420 touch.Decompose(events, opt); 421 if (events.empty()) { 422 return; 423 } 424 auto displayId = events.begin()->point_.displayId_; 425 if (!CheckDisplayExist(displayId)) { 426 LOG_E("No display: %{public}d", displayId); 427 err = ApiCallErr(ERR_INVALID_INPUT, "Invalid display id."); 428 return; 429 } 430 uiController_->InjectMouseEventSequence(events); 431 } 432 TakeScreenCap(int32_t fd,ApiCallErr & err,Rect rect,int32_t displayId)433 void UiDriver::TakeScreenCap(int32_t fd, ApiCallErr &err, Rect rect, int32_t displayId) 434 { 435 if (!CheckStatus(false, err)) { 436 return; 437 } 438 stringstream errorRecv; 439 if (!uiController_->TakeScreenCap(fd, errorRecv, displayId, rect)) { 440 string errStr = errorRecv.str(); 441 LOG_W("ScreenCap failed: %{public}s", errStr.c_str()); 442 if (errStr.find("File opening failed") == 0) { 443 err = ApiCallErr(ERR_INVALID_INPUT, "Invalid save path or permission denied"); 444 } else { 445 err = ApiCallErr(ERR_INTERNAL, errStr); 446 } 447 LOG_W("ScreenCap failed: %{public}s", errorRecv.str().c_str()); 448 } else { 449 LOG_D("ScreenCap successed"); 450 } 451 } 452 FindWindow(function<bool (const Window &)> matcher,ApiCallErr & err)453 unique_ptr<Window> UiDriver::FindWindow(function<bool(const Window &)> matcher, ApiCallErr &err) 454 { 455 UpdateUIWindows(err); 456 if (err.code_ != NO_ERROR) { 457 return nullptr; 458 } 459 for (auto &dm : displayToWindowCacheMap_) { 460 auto &windowCacheVec = dm.second; 461 for (auto &windowCache : windowCacheVec) { 462 if (matcher(windowCache.window_)) { 463 auto clone = make_unique<Window>(0); 464 *clone = windowCache.window_; // copy construct 465 return clone; 466 } 467 } 468 } 469 return nullptr; 470 } 471 RetrieveWindow(const Window & window,ApiCallErr & err)472 const Window *UiDriver::RetrieveWindow(const Window &window, ApiCallErr &err) 473 { 474 UpdateUIWindows(err, window.displayId_); 475 if (err.code_ != NO_ERROR) { 476 return nullptr; 477 } 478 auto dm = displayToWindowCacheMap_.find(window.displayId_); 479 auto &windowCacheVec = dm->second; 480 for (auto &winCache : windowCacheVec) { 481 if (winCache.window_.id_ != window.id_) { 482 continue; 483 } 484 return &winCache.window_; 485 } 486 stringstream msg; 487 msg << "Display " << window.displayId_; 488 msg << "Window " << window.id_; 489 msg << "dose not exist on current UI! Check if the UI has changed after you got the window object"; 490 err = ApiCallErr(ERR_COMPONENT_LOST, msg.str()); 491 LOG_W("%{public}s", err.message_.c_str()); 492 return nullptr; 493 } 494 SetDisplayRotation(DisplayRotation rotation,ApiCallErr & error)495 void UiDriver::SetDisplayRotation(DisplayRotation rotation, ApiCallErr &error) 496 { 497 if (!CheckStatus(false, error)) { 498 return; 499 } 500 uiController_->SetDisplayRotation(rotation); 501 } 502 GetDisplayRotation(ApiCallErr & error,int32_t displayId)503 DisplayRotation UiDriver::GetDisplayRotation(ApiCallErr &error, int32_t displayId) 504 { 505 if (!CheckStatus(false, error)) { 506 return ROTATION_0; 507 } 508 return uiController_->GetDisplayRotation(displayId); 509 } 510 SetDisplayRotationEnabled(bool enabled,ApiCallErr & error)511 void UiDriver::SetDisplayRotationEnabled(bool enabled, ApiCallErr &error) 512 { 513 if (!CheckStatus(false, error)) { 514 return; 515 } 516 uiController_->SetDisplayRotationEnabled(enabled); 517 } 518 WaitForUiSteady(uint32_t idleThresholdMs,uint32_t timeoutSec,ApiCallErr & error)519 bool UiDriver::WaitForUiSteady(uint32_t idleThresholdMs, uint32_t timeoutSec, ApiCallErr &error) 520 { 521 if (!CheckStatus(false, error)) { 522 return false; 523 } 524 return uiController_->WaitForUiSteady(idleThresholdMs, timeoutSec); 525 } 526 WakeUpDisplay(ApiCallErr & error)527 void UiDriver::WakeUpDisplay(ApiCallErr &error) 528 { 529 if (!CheckStatus(false, error)) { 530 return; 531 } 532 if (uiController_->IsScreenOn()) { 533 return; 534 } else { 535 LOG_D("screen is off, turn it on"); 536 UiOpArgs uiOpArgs; 537 this->TriggerKey(Power(), uiOpArgs, error); 538 } 539 } 540 GetDisplaySize(ApiCallErr & error,int32_t displayId)541 Point UiDriver::GetDisplaySize(ApiCallErr &error, int32_t displayId) 542 { 543 if (!CheckStatus(false, error)) { 544 return Point(0, 0); 545 } 546 return uiController_->GetDisplaySize(displayId); 547 } 548 GetDisplayDensity(ApiCallErr & error,int32_t displayId)549 Point UiDriver::GetDisplayDensity(ApiCallErr &error, int32_t displayId) 550 { 551 if (!CheckStatus(false, error)) { 552 return Point(0, 0); 553 } 554 return uiController_->GetDisplayDensity(displayId); 555 } 556 TextToKeyEvents(string_view text,std::vector<KeyEvent> & events,ApiCallErr & error)557 bool UiDriver::TextToKeyEvents(string_view text, std::vector<KeyEvent> &events, ApiCallErr &error) 558 { 559 if (!CheckStatus(false, error)) { 560 return false; 561 } 562 static constexpr uint32_t typeCharTimeMs = 50; 563 if (!text.empty()) { 564 vector<char> chars(text.begin(), text.end()); // decompose to sing-char input sequence 565 vector<pair<int32_t, int32_t>> keyCodes; 566 for (auto ch : chars) { 567 int32_t code = KEYCODE_NONE; 568 int32_t ctrlCode = KEYCODE_NONE; 569 if (!uiController_->GetCharKeyCode(ch, code, ctrlCode)) { 570 return false; 571 } 572 keyCodes.emplace_back(make_pair(code, ctrlCode)); 573 } 574 for (auto &pair : keyCodes) { 575 if (pair.second != KEYCODE_NONE) { 576 events.emplace_back(KeyEvent {ActionStage::DOWN, pair.second, 0}); 577 } 578 events.emplace_back(KeyEvent {ActionStage::DOWN, pair.first, typeCharTimeMs}); 579 if (pair.second != KEYCODE_NONE) { 580 events.emplace_back(KeyEvent {ActionStage::UP, pair.second, 0}); 581 } 582 events.emplace_back(KeyEvent {ActionStage::UP, pair.first, 0}); 583 } 584 } 585 return true; 586 } 587 InputText(string_view text,ApiCallErr & error,const UiOpArgs & opt,int32_t displayId)588 void UiDriver::InputText(string_view text, ApiCallErr &error, const UiOpArgs &opt, int32_t displayId) 589 { 590 if (text.empty()) { 591 return; 592 } 593 vector<KeyEvent> events; 594 constexpr auto maxKeyEventCounts = 200; 595 if (!TextToKeyEvents(text, events, error) || opt.inputByPasteBoard_ || text.length() > maxKeyEventCounts) { 596 LOG_D("inputText by pasteBoard"); 597 uiController_->PutTextToClipboard(text, error); 598 if (error.code_ != NO_ERROR) { 599 return; 600 } 601 auto actionForPatse = CombinedKeys(KEYCODE_CTRL, KEYCODE_V, KEYCODE_NONE); 602 TriggerKey(actionForPatse, opt, error, displayId); 603 } else { 604 LOG_D("inputText by Keycode"); 605 auto keyActionForInput = KeysForwarder(events); 606 TriggerKey(keyActionForInput, opt, error, displayId); 607 } 608 } 609 PerformTouchPadAction(const TouchPadAction & touch,const UiOpArgs & opt,ApiCallErr & error)610 void UiDriver::PerformTouchPadAction(const TouchPadAction &touch, const UiOpArgs &opt, ApiCallErr &error) 611 { 612 if (!CheckStatus(false, error)) { 613 return; 614 } 615 if (!uiController_->IsTouchPadExist()) { 616 error = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "This device can not support this action"); 617 return; 618 } 619 vector<TouchPadEvent> events; 620 touch.Decompose(events, opt, uiController_->GetDisplaySize(0)); 621 if (events.empty()) { 622 return; 623 } 624 uiController_->InjectTouchPadEventSequence(events); 625 } 626 PerformPenTouch(const TouchAction & touch,const UiOpArgs & opt,ApiCallErr & err)627 void UiDriver::PerformPenTouch(const TouchAction &touch, const UiOpArgs &opt, ApiCallErr &err) 628 { 629 if (!CheckStatus(false, err)) { 630 return; 631 } 632 if (opt.touchPressure_ < 0 || opt.touchPressure_ > 1) { 633 err = ApiCallErr(ERR_INVALID_INPUT, "Pressure must ranges form 0 to 1"); 634 return; 635 } 636 PointerMatrix events; 637 touch.Decompose(events, opt); 638 PointerMatrix eventsInPen(1, events.GetSteps() + INDEX_TWO); 639 eventsInPen.SetTouchPressure(opt.touchPressure_); 640 events.ConvertToPenEvents(eventsInPen); 641 if (eventsInPen.Empty()) { 642 return; 643 } 644 auto displayId = eventsInPen.At(0, 0).point_.displayId_; 645 if (!CheckDisplayExist(displayId)) { 646 LOG_E("No display: %{public}d", displayId); 647 err = ApiCallErr(ERR_INVALID_INPUT, "Invalid display id."); 648 return; 649 } 650 uiController_->InjectTouchEventSequence(eventsInPen); 651 } 652 SetAamsWorkMode(const AamsWorkMode mode)653 void UiDriver::SetAamsWorkMode(const AamsWorkMode mode) 654 { 655 mode_ = mode; 656 } 657 IsWearable()658 bool UiDriver::IsWearable() 659 { 660 return uiController_->IsWearable(); 661 } 662 IsAdjustWindowModeEnable()663 bool UiDriver::IsAdjustWindowModeEnable() 664 { 665 return uiController_->IsAdjustWindowModeEnable(); 666 } 667 CheckDisplayExist(int32_t displayId)668 bool UiDriver::CheckDisplayExist(int32_t displayId) 669 { 670 return uiController_->CheckDisplayExist(displayId); 671 } 672 CloseAamsEvent()673 void UiDriver::CloseAamsEvent() 674 { 675 eventObserverEnable_ = false; 676 return uiController_->CloseAamsEvent(); 677 } 678 OpenAamsEvent()679 void UiDriver::OpenAamsEvent() 680 { 681 eventObserverEnable_ = true; 682 return uiController_->OpenAamsEvent(); 683 } 684 GetEventObserverEnable()685 bool UiDriver::GetEventObserverEnable() 686 { 687 return eventObserverEnable_; 688 } 689 ChangeWindowMode(int32_t windowId,WindowMode mode)690 void UiDriver::ChangeWindowMode(int32_t windowId, WindowMode mode) 691 { 692 return uiController_->ChangeWindowMode(windowId, mode); 693 } 694 } // namespace OHOS::uitest 695