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)301 void UiDriver::TriggerKey(const KeyAction &key, const UiOpArgs &opt, ApiCallErr &error) 302 { 303 if (!CheckStatus(false, error)) { 304 return; 305 } 306 vector<KeyEvent> events; 307 key.ComputeEvents(events, opt); 308 if (events.empty()) { 309 return; 310 } 311 uiController_->InjectKeyEventSequence(events); 312 } 313 FindWidgets(const WidgetSelector & selector,vector<unique_ptr<Widget>> & rev,ApiCallErr & err,bool updateUi)314 void UiDriver::FindWidgets(const WidgetSelector &selector, vector<unique_ptr<Widget>> &rev, 315 ApiCallErr &err, bool updateUi) 316 { 317 UiOpArgs opt; 318 uiController_->WaitForUiSteady(opt.uiSteadyThresholdMs_, opt.waitUiSteadyMaxMs_); 319 if (updateUi) { 320 UpdateUIWindows(err, selector.GetDisplayLocator()); 321 if (err.code_ != NO_ERROR) { 322 return; 323 } 324 } else { 325 visitWidgets_.clear(); 326 targetWidgetsIndex_.clear(); 327 } 328 auto appLocator = selector.GetAppLocator(); 329 for (auto &dm : displayToWindowCacheMap_) { 330 auto &windowCacheVec = dm.second; 331 for (auto &curWinCache : windowCacheVec) { 332 if (appLocator != "" && curWinCache.window_.bundleName_ != appLocator) { 333 continue; 334 } 335 if (curWinCache.widgetIterator_ == nullptr && 336 !uiController_->GetWidgetsInWindow(curWinCache.window_, curWinCache.widgetIterator_, mode_)) { 337 continue; 338 } 339 selector.Select(curWinCache.window_, *curWinCache.widgetIterator_, visitWidgets_, targetWidgetsIndex_); 340 if (!selector.IsWantMulti() && !targetWidgetsIndex_.empty()) { 341 break; 342 } 343 if (!selector.IsWantMulti()) { 344 visitWidgets_.clear(); 345 targetWidgetsIndex_.clear(); 346 } 347 } 348 if (!selector.IsWantMulti() && !targetWidgetsIndex_.empty()) { 349 break; 350 } 351 } 352 if (targetWidgetsIndex_.empty()) { 353 LOG_W("self node not found by %{public}s", selector.Describe().data()); 354 return; 355 } 356 // covert widgets to images as return value 357 uint32_t index = 0; 358 for (auto targetIndex : targetWidgetsIndex_) { 359 auto image = CloneFreeWidget(visitWidgets_[targetIndex], selector.Describe()); 360 // at sometime, more than one widgets are found, add the node index to the description 361 rev.emplace_back(move(image)); 362 index++; 363 } 364 } 365 WaitForWidget(const WidgetSelector & selector,const UiOpArgs & opt,ApiCallErr & err)366 unique_ptr<Widget> UiDriver::WaitForWidget(const WidgetSelector &selector, const UiOpArgs &opt, ApiCallErr &err) 367 { 368 const uint32_t sliceMs = 20; 369 const auto startMs = GetCurrentMillisecond(); 370 vector<unique_ptr<Widget>> receiver; 371 do { 372 FindWidgets(selector, receiver, err); 373 if (err.code_ != NO_ERROR) { // abort on error 374 return nullptr; 375 } 376 if (!receiver.empty()) { 377 return move(receiver.at(0)); 378 } 379 DelayMs(sliceMs); 380 } while (GetCurrentMillisecond() - startMs < opt.waitWidgetMaxMs_); 381 return nullptr; 382 } 383 DelayMs(uint32_t ms)384 void UiDriver::DelayMs(uint32_t ms) 385 { 386 if (ms > 0) { 387 this_thread::sleep_for(chrono::milliseconds(ms)); 388 } 389 } 390 PerformTouch(const TouchAction & touch,const UiOpArgs & opt,ApiCallErr & err)391 void UiDriver::PerformTouch(const TouchAction &touch, const UiOpArgs &opt, ApiCallErr &err) 392 { 393 if (!CheckStatus(false, err)) { 394 return; 395 } 396 PointerMatrix events; 397 touch.Decompose(events, opt); 398 if (events.Empty()) { 399 return; 400 } 401 uiController_->InjectTouchEventSequence(events); 402 } 403 PerformMouseAction(const MouseAction & touch,const UiOpArgs & opt,ApiCallErr & err)404 void UiDriver::PerformMouseAction(const MouseAction &touch, const UiOpArgs &opt, ApiCallErr &err) 405 { 406 if (!CheckStatus(false, err)) { 407 return; 408 } 409 vector<MouseEvent> events; 410 touch.Decompose(events, opt); 411 if (events.empty()) { 412 return; 413 } 414 uiController_->InjectMouseEventSequence(events); 415 } 416 TakeScreenCap(int32_t fd,ApiCallErr & err,Rect rect,int32_t displayId)417 void UiDriver::TakeScreenCap(int32_t fd, ApiCallErr &err, Rect rect, int32_t displayId) 418 { 419 if (!CheckStatus(false, err)) { 420 return; 421 } 422 stringstream errorRecv; 423 if (!uiController_->TakeScreenCap(fd, errorRecv, displayId, rect)) { 424 string errStr = errorRecv.str(); 425 LOG_W("ScreenCap failed: %{public}s", errStr.c_str()); 426 if (errStr.find("File opening failed") == 0) { 427 err = ApiCallErr(ERR_INVALID_INPUT, "Invalid save path or permission denied"); 428 } else { 429 err = ApiCallErr(ERR_INTERNAL, errStr); 430 } 431 LOG_W("ScreenCap failed: %{public}s", errorRecv.str().c_str()); 432 } else { 433 LOG_D("ScreenCap successed"); 434 } 435 } 436 FindWindow(function<bool (const Window &)> matcher,ApiCallErr & err)437 unique_ptr<Window> UiDriver::FindWindow(function<bool(const Window &)> matcher, ApiCallErr &err) 438 { 439 UpdateUIWindows(err); 440 if (err.code_ != NO_ERROR) { 441 return nullptr; 442 } 443 for (auto &dm : displayToWindowCacheMap_) { 444 auto &windowCacheVec = dm.second; 445 for (auto &windowCache : windowCacheVec) { 446 if (matcher(windowCache.window_)) { 447 auto clone = make_unique<Window>(0); 448 *clone = windowCache.window_; // copy construct 449 return clone; 450 } 451 } 452 } 453 return nullptr; 454 } 455 RetrieveWindow(const Window & window,ApiCallErr & err)456 const Window *UiDriver::RetrieveWindow(const Window &window, ApiCallErr &err) 457 { 458 UpdateUIWindows(err, window.displayId_); 459 if (err.code_ != NO_ERROR) { 460 return nullptr; 461 } 462 auto dm = displayToWindowCacheMap_.find(window.displayId_); 463 auto &windowCacheVec = dm->second; 464 for (auto &winCache : windowCacheVec) { 465 if (winCache.window_.id_ != window.id_) { 466 continue; 467 } 468 return &winCache.window_; 469 } 470 stringstream msg; 471 msg << "Display " << window.displayId_; 472 msg << "Window " << window.id_; 473 msg << "dose not exist on current UI! Check if the UI has changed after you got the window object"; 474 err = ApiCallErr(ERR_COMPONENT_LOST, msg.str()); 475 LOG_W("%{public}s", err.message_.c_str()); 476 return nullptr; 477 } 478 SetDisplayRotation(DisplayRotation rotation,ApiCallErr & error)479 void UiDriver::SetDisplayRotation(DisplayRotation rotation, ApiCallErr &error) 480 { 481 if (!CheckStatus(false, error)) { 482 return; 483 } 484 uiController_->SetDisplayRotation(rotation); 485 } 486 GetDisplayRotation(ApiCallErr & error,int32_t displayId)487 DisplayRotation UiDriver::GetDisplayRotation(ApiCallErr &error, int32_t displayId) 488 { 489 if (!CheckStatus(false, error)) { 490 return ROTATION_0; 491 } 492 return uiController_->GetDisplayRotation(displayId); 493 } 494 SetDisplayRotationEnabled(bool enabled,ApiCallErr & error)495 void UiDriver::SetDisplayRotationEnabled(bool enabled, ApiCallErr &error) 496 { 497 if (!CheckStatus(false, error)) { 498 return; 499 } 500 uiController_->SetDisplayRotationEnabled(enabled); 501 } 502 WaitForUiSteady(uint32_t idleThresholdMs,uint32_t timeoutSec,ApiCallErr & error)503 bool UiDriver::WaitForUiSteady(uint32_t idleThresholdMs, uint32_t timeoutSec, ApiCallErr &error) 504 { 505 if (!CheckStatus(false, error)) { 506 return false; 507 } 508 return uiController_->WaitForUiSteady(idleThresholdMs, timeoutSec); 509 } 510 WakeUpDisplay(ApiCallErr & error)511 void UiDriver::WakeUpDisplay(ApiCallErr &error) 512 { 513 if (!CheckStatus(false, error)) { 514 return; 515 } 516 if (uiController_->IsScreenOn()) { 517 return; 518 } else { 519 LOG_D("screen is off, turn it on"); 520 UiOpArgs uiOpArgs; 521 this->TriggerKey(Power(), uiOpArgs, error); 522 } 523 } 524 GetDisplaySize(ApiCallErr & error,int32_t displayId)525 Point UiDriver::GetDisplaySize(ApiCallErr &error, int32_t displayId) 526 { 527 if (!CheckStatus(false, error)) { 528 return Point(0, 0); 529 } 530 return uiController_->GetDisplaySize(displayId); 531 } 532 GetDisplayDensity(ApiCallErr & error,int32_t displayId)533 Point UiDriver::GetDisplayDensity(ApiCallErr &error, int32_t displayId) 534 { 535 if (!CheckStatus(false, error)) { 536 return Point(0, 0); 537 } 538 return uiController_->GetDisplayDensity(displayId); 539 } 540 TextToKeyEvents(string_view text,std::vector<KeyEvent> & events,ApiCallErr & error)541 bool UiDriver::TextToKeyEvents(string_view text, std::vector<KeyEvent> &events, ApiCallErr &error) 542 { 543 if (!CheckStatus(false, error)) { 544 return false; 545 } 546 static constexpr uint32_t typeCharTimeMs = 50; 547 if (!text.empty()) { 548 vector<char> chars(text.begin(), text.end()); // decompose to sing-char input sequence 549 vector<pair<int32_t, int32_t>> keyCodes; 550 for (auto ch : chars) { 551 int32_t code = KEYCODE_NONE; 552 int32_t ctrlCode = KEYCODE_NONE; 553 if (!uiController_->GetCharKeyCode(ch, code, ctrlCode)) { 554 return false; 555 } 556 keyCodes.emplace_back(make_pair(code, ctrlCode)); 557 } 558 for (auto &pair : keyCodes) { 559 if (pair.second != KEYCODE_NONE) { 560 events.emplace_back(KeyEvent {ActionStage::DOWN, pair.second, 0}); 561 } 562 events.emplace_back(KeyEvent {ActionStage::DOWN, pair.first, typeCharTimeMs}); 563 if (pair.second != KEYCODE_NONE) { 564 events.emplace_back(KeyEvent {ActionStage::UP, pair.second, 0}); 565 } 566 events.emplace_back(KeyEvent {ActionStage::UP, pair.first, 0}); 567 } 568 } 569 return true; 570 } 571 InputText(string_view text,ApiCallErr & error)572 void UiDriver::InputText(string_view text, ApiCallErr &error) 573 { 574 vector<KeyEvent> events; 575 UiOpArgs uiOpArgs; 576 if (!text.empty()) { 577 constexpr auto maxKeyEventCounts = 200; 578 if (text.length() < maxKeyEventCounts && TextToKeyEvents(text, events, error)) { 579 LOG_D("inputText by Keycode"); 580 auto keyActionForInput = KeysForwarder(events); 581 TriggerKey(keyActionForInput, uiOpArgs, error); 582 } else { 583 uiController_->PutTextToClipboard(text); 584 LOG_D("inputText by pasteBoard"); 585 auto actionForPatse = CombinedKeys(KEYCODE_CTRL, KEYCODE_V, KEYCODE_NONE); 586 TriggerKey(actionForPatse, uiOpArgs, error); 587 } 588 } 589 } 590 PerformTouchPadAction(const TouchPadAction & touch,const UiOpArgs & opt,ApiCallErr & error)591 void UiDriver::PerformTouchPadAction(const TouchPadAction &touch, const UiOpArgs &opt, ApiCallErr &error) 592 { 593 if (!CheckStatus(false, error)) { 594 return; 595 } 596 if (!uiController_->IsTouchPadExist()) { 597 error = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "This device can not support this action"); 598 return; 599 } 600 vector<TouchPadEvent> events; 601 touch.Decompose(events, opt, uiController_->GetDisplaySize(0)); 602 if (events.empty()) { 603 return; 604 } 605 uiController_->InjectTouchPadEventSequence(events); 606 } 607 PerformPenTouch(const TouchAction & touch,const UiOpArgs & opt,ApiCallErr & err)608 void UiDriver::PerformPenTouch(const TouchAction &touch, const UiOpArgs &opt, ApiCallErr &err) 609 { 610 if (!CheckStatus(false, err)) { 611 return; 612 } 613 if (opt.touchPressure_ < 0 || opt.touchPressure_ > 1) { 614 err = ApiCallErr(ERR_INVALID_INPUT, "Pressure must ranges form 0 to 1"); 615 return; 616 } 617 PointerMatrix events; 618 touch.Decompose(events, opt); 619 PointerMatrix eventsInPen(1, events.GetSteps() + INDEX_TWO); 620 eventsInPen.SetTouchPressure(opt.touchPressure_); 621 events.ConvertToPenEvents(eventsInPen); 622 if (eventsInPen.Empty()) { 623 return; 624 } 625 uiController_->InjectTouchEventSequence(eventsInPen); 626 } 627 SetAamsWorkMode(const AamsWorkMode mode)628 void UiDriver::SetAamsWorkMode(const AamsWorkMode mode) 629 { 630 mode_ = mode; 631 } 632 } // namespace OHOS::uitest 633