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 <atomic> 17 #include <chrono> 18 #include <fstream> 19 #include <memory> 20 #include <iostream> 21 #include <thread> 22 #include <utility> 23 #include <condition_variable> 24 #include "accessibility_event_info.h" 25 #include "accessibility_ui_test_ability.h" 26 #include "display_manager.h" 27 #include "screen_manager.h" 28 #include "input_manager.h" 29 #include "png.h" 30 #include "wm_common.h" 31 #include "system_ui_controller.h" 32 33 using namespace std; 34 using namespace chrono; 35 36 namespace OHOS::uitest { 37 using namespace std; 38 using namespace nlohmann; 39 using namespace OHOS::MMI; 40 using namespace OHOS::Accessibility; 41 using namespace OHOS::Rosen; 42 using namespace OHOS::Media; 43 44 class UiEventMonitor final : public AccessibleAbilityListener { 45 public: 46 virtual ~UiEventMonitor() override = default; 47 48 void OnAbilityConnected() override; 49 50 void OnAbilityDisconnected() override; 51 52 void OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo) override; 53 54 void SetOnAbilityConnectCallback(function<void()> onConnectCb); 55 56 void SetOnAbilityDisConnectCallback(function<void()> onDisConnectCb); 57 OnKeyPressEvent(const shared_ptr<MMI::KeyEvent> & keyEvent)58 bool OnKeyPressEvent(const shared_ptr<MMI::KeyEvent> &keyEvent) override 59 { 60 return false; 61 } 62 63 uint64_t GetLastEventMillis(); 64 65 bool WaitEventIdle(uint32_t idleThresholdMs, uint32_t timeoutMs); 66 67 private: 68 function<void()> onConnectCallback_ = nullptr; 69 function<void()> onDisConnectCallback_ = nullptr; 70 atomic<uint64_t> lastEventMillis_ = 0; 71 }; 72 SetOnAbilityConnectCallback(function<void ()> onConnectCb)73 void UiEventMonitor::SetOnAbilityConnectCallback(function<void()> onConnectCb) 74 { 75 onConnectCallback_ = std::move(onConnectCb); 76 } 77 SetOnAbilityDisConnectCallback(function<void ()> onDisConnectCb)78 void UiEventMonitor::SetOnAbilityDisConnectCallback(function<void()> onDisConnectCb) 79 { 80 onDisConnectCallback_ = std::move(onDisConnectCb); 81 } 82 OnAbilityConnected()83 void UiEventMonitor::OnAbilityConnected() 84 { 85 if (onConnectCallback_ != nullptr) { 86 onConnectCallback_(); 87 } 88 } 89 OnAbilityDisconnected()90 void UiEventMonitor::OnAbilityDisconnected() 91 { 92 if (onDisConnectCallback_ != nullptr) { 93 onDisConnectCallback_(); 94 } 95 } 96 97 // the monitored events 98 static constexpr uint32_t EVENT_MASK = EventType::TYPE_VIEW_TEXT_UPDATE_EVENT | 99 EventType::TYPE_PAGE_STATE_UPDATE | 100 EventType::TYPE_PAGE_CONTENT_UPDATE | 101 EventType::TYPE_VIEW_SCROLLED_EVENT | 102 EventType::TYPE_WINDOW_UPDATE; 103 OnAccessibilityEvent(const AccessibilityEventInfo & eventInfo)104 void UiEventMonitor::OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo) 105 { 106 LOG_W("OnEvent:0x%{public}x", eventInfo.GetEventType()); 107 if ((eventInfo.GetEventType() & EVENT_MASK) > 0) { 108 lastEventMillis_.store(GetCurrentMillisecond()); 109 } 110 } 111 GetLastEventMillis()112 uint64_t UiEventMonitor::GetLastEventMillis() 113 { 114 if (lastEventMillis_.load() <= 0) { 115 lastEventMillis_.store(GetCurrentMillisecond()); 116 } 117 return lastEventMillis_.load(); 118 } 119 WaitEventIdle(uint32_t idleThresholdMs,uint32_t timeoutMs)120 bool UiEventMonitor::WaitEventIdle(uint32_t idleThresholdMs, uint32_t timeoutMs) 121 { 122 const auto currentMs = GetCurrentMillisecond(); 123 if (lastEventMillis_.load() <= 0) { 124 lastEventMillis_.store(currentMs); 125 } 126 if (currentMs - lastEventMillis_.load() >= idleThresholdMs) { 127 return true; 128 } 129 static constexpr auto sliceMs = 10; 130 this_thread::sleep_for(chrono::milliseconds(sliceMs)); 131 if (timeoutMs <= sliceMs) { 132 return false; 133 } 134 return WaitEventIdle(idleThresholdMs, timeoutMs - sliceMs); 135 } 136 SysUiController(string_view name)137 SysUiController::SysUiController(string_view name) : UiController(name) {} 138 ~SysUiController()139 SysUiController::~SysUiController() 140 { 141 DisConnectFromSysAbility(); 142 } 143 GenerateNodeHash(AccessibilityElementInfo & node)144 static size_t GenerateNodeHash(AccessibilityElementInfo &node) 145 { 146 static constexpr auto SHIFT_BITS = 32U; 147 static constexpr auto hashFunc = hash<string>(); 148 int64_t intId = node.GetWindowId(); 149 intId = (intId << SHIFT_BITS) + node.GetAccessibilityId(); 150 const string strId = node.GetBundleName() + node.GetComponentType() + to_string(intId); 151 return hashFunc(strId); 152 } 153 MarshalAccessibilityNodeAttributes(AccessibilityElementInfo & node,json & to)154 static void MarshalAccessibilityNodeAttributes(AccessibilityElementInfo &node, json &to) 155 { 156 to[ATTR_NAMES[UiAttr::HASHCODE].data()] = to_string(GenerateNodeHash(node)); 157 to[ATTR_NAMES[UiAttr::TEXT].data()] = node.GetContent(); 158 to[ATTR_NAMES[UiAttr::ACCESSIBILITY_ID].data()] = to_string(node.GetAccessibilityId()); 159 to[ATTR_NAMES[UiAttr::ID].data()] = node.GetInspectorKey(); 160 to[ATTR_NAMES[UiAttr::KEY].data()] = node.GetInspectorKey(); 161 to[ATTR_NAMES[UiAttr::TYPE].data()] = node.GetComponentType(); 162 to[ATTR_NAMES[UiAttr::ENABLED].data()] = node.IsEnabled() ? "true" : "false"; 163 to[ATTR_NAMES[UiAttr::FOCUSED].data()] = node.IsFocused() ? "true" : "false"; 164 to[ATTR_NAMES[UiAttr::SELECTED].data()] = node.IsSelected() ? "true" : "false"; 165 to[ATTR_NAMES[UiAttr::CHECKABLE].data()] = node.IsCheckable() ? "true" : "false"; 166 to[ATTR_NAMES[UiAttr::CHECKED].data()] = node.IsChecked() ? "true" : "false"; 167 to[ATTR_NAMES[UiAttr::CLICKABLE].data()] = "false"; 168 to[ATTR_NAMES[UiAttr::LONG_CLICKABLE].data()] = "false"; 169 to[ATTR_NAMES[UiAttr::SCROLLABLE].data()] = "false"; 170 to[ATTR_NAMES[UiAttr::HOST_WINDOW_ID].data()] = to_string(node.GetWindowId()); 171 const auto bounds = node.GetRectInScreen(); 172 const auto rect = Rect(bounds.GetLeftTopXScreenPostion(), bounds.GetRightBottomXScreenPostion(), 173 bounds.GetLeftTopYScreenPostion(), bounds.GetRightBottomYScreenPostion()); 174 stringstream stream; 175 // "[%d,%d][%d,%d]", rect.left, rect.top, rect.right, rect.bottom 176 stream << "[" << rect.left_ << "," << rect.top_ << "]" << "[" << rect.right_ << "," << rect.bottom_ << "]"; 177 to[ATTR_NAMES[UiAttr::BOUNDS].data()] = stream.str(); 178 auto actionList = node.GetActionList(); 179 for (auto &action : actionList) { 180 switch (action.GetActionType()) { 181 case ACCESSIBILITY_ACTION_CLICK: 182 to[ATTR_NAMES[UiAttr::CLICKABLE].data()] = "true"; 183 break; 184 case ACCESSIBILITY_ACTION_LONG_CLICK: 185 to[ATTR_NAMES[UiAttr::LONG_CLICKABLE].data()] = "true"; 186 break; 187 case ACCESSIBILITY_ACTION_SCROLL_FORWARD: 188 case ACCESSIBILITY_ACTION_SCROLL_BACKWARD: 189 to[ATTR_NAMES[UiAttr::SCROLLABLE].data()] = "true"; 190 break; 191 default: 192 break; 193 } 194 } 195 } 196 MarshallAccessibilityNodeInfo(AccessibilityElementInfo & from,json & to,int32_t index,bool isDecorBar)197 static void MarshallAccessibilityNodeInfo(AccessibilityElementInfo &from, json &to, int32_t index, bool isDecorBar) 198 { 199 json attributes; 200 MarshalAccessibilityNodeAttributes(from, attributes); 201 if (isDecorBar || from.GetInspectorKey() == "ContainerModalTitleRow") { 202 attributes[ATTR_NAMES[UiAttr::TYPE].data()] = "DecorBar"; 203 } 204 attributes["index"] = to_string(index); 205 to["attributes"] = attributes; 206 auto childList = json::array(); 207 const auto childCount = from.GetChildCount(); 208 AccessibilityElementInfo child; 209 auto ability = AccessibilityUITestAbility::GetInstance(); 210 for (auto idx = 0; idx < childCount; idx++) { 211 auto ret = ability->GetChildElementInfo(idx, from, child); 212 if (ret == RET_OK) { 213 isDecorBar = false; 214 if (child.GetComponentType() == "rootdecortag") { 215 AccessibilityElementInfo child2; 216 (ability->GetChildElementInfo(0, child, child2) == RET_OK && child2.IsVisible()) || 217 (ability->GetChildElementInfo(1, child, child2) == RET_OK && child2.IsVisible()); 218 child = child2; 219 isDecorBar = true; 220 } 221 if (!child.IsVisible()) { 222 LOG_I("invisible node drop, id: %{public}d", child.GetAccessibilityId()); 223 continue; 224 } 225 auto parcel = json(); 226 MarshallAccessibilityNodeInfo(child, parcel, idx, isDecorBar); 227 childList.push_back(parcel); 228 } else { 229 LOG_W("Get Node child at index=%{public}d failed", idx); 230 } 231 } 232 to["children"] = childList; 233 } 234 InflateWindowInfo(AccessibilityWindowInfo & node,Window & info)235 static void InflateWindowInfo(AccessibilityWindowInfo& node, Window& info) 236 { 237 info.focused_ = node.IsFocused(); 238 info.actived_ = node.IsActive(); 239 info.decoratorEnabled_ = node.IsDecorEnable(); 240 auto rect = node.GetRectInScreen(); 241 info.bounds_ = Rect(rect.GetLeftTopXScreenPostion(), rect.GetRightBottomXScreenPostion(), 242 rect.GetLeftTopYScreenPostion(), rect.GetRightBottomYScreenPostion()); 243 info.mode_ = WindowMode::UNKNOWN; 244 const auto origMode = static_cast<OHOS::Rosen::WindowMode>(node.GetWindowMode()); 245 switch (origMode) { 246 case OHOS::Rosen::WindowMode::WINDOW_MODE_FULLSCREEN: 247 info.mode_ = WindowMode::FULLSCREEN; 248 break; 249 case OHOS::Rosen::WindowMode::WINDOW_MODE_SPLIT_PRIMARY: 250 info.mode_ = WindowMode::SPLIT_PRIMARY; 251 break; 252 case OHOS::Rosen::WindowMode::WINDOW_MODE_SPLIT_SECONDARY: 253 info.mode_ = WindowMode::SPLIT_SECONDARY; 254 break; 255 case OHOS::Rosen::WindowMode::WINDOW_MODE_FLOATING: 256 info.mode_ = WindowMode::FLOATING; 257 break; 258 case OHOS::Rosen::WindowMode::WINDOW_MODE_PIP: 259 info.mode_ = WindowMode::PIP; 260 break; 261 default: 262 info.mode_ = WindowMode::UNKNOWN; 263 break; 264 } 265 } 266 GetUiHierarchy(vector<pair<Window,nlohmann::json>> & out)267 void SysUiController::GetUiHierarchy(vector<pair<Window, nlohmann::json>> &out) 268 { 269 if (!connected_) { 270 LOG_I("Not connect to AccessibilityUITestAbility, try to connect it"); 271 if (!this->ConnectToSysAbility()) { 272 LOG_W("Connect to AccessibilityUITestAbility failed"); 273 return; 274 } 275 } 276 auto ability = AccessibilityUITestAbility::GetInstance(); 277 vector<AccessibilityWindowInfo> windows; 278 if (ability->GetWindows(windows) != RET_OK) { 279 LOG_W("GetWindows from AccessibilityUITestAbility failed"); 280 return; 281 } 282 sort(windows.begin(), windows.end(), [](auto &w1, auto &w2) -> bool { 283 return w1.GetWindowLayer() > w2.GetWindowLayer(); 284 }); 285 AccessibilityElementInfo elementInfo; 286 for (auto &window : windows) { 287 if (ability->GetRootByWindow(window, elementInfo) == RET_OK) { 288 const auto app = elementInfo.GetBundleName(); 289 LOG_D("Get window at layer %{public}d, appId: %{public}s", window.GetWindowLayer(), app.c_str()); 290 auto winInfo = Window(window.GetWindowId()); 291 InflateWindowInfo(window, winInfo); 292 winInfo.bundleName_ = app; 293 // apply window bounds as root node bounds 294 auto windowBounds = window.GetRectInScreen(); 295 elementInfo.SetRectInScreen(windowBounds); 296 auto root = nlohmann::json(); 297 MarshallAccessibilityNodeInfo(elementInfo, root, 0, false); 298 out.push_back(make_pair(move(winInfo), move(root))); 299 } else { 300 LOG_W("GetRootByWindow failed"); 301 } 302 } 303 } 304 305 InjectTouchEventSequence(const PointerMatrix & events) const306 void SysUiController::InjectTouchEventSequence(const PointerMatrix &events) const 307 { 308 for (uint32_t step = 0; step < events.GetSteps(); step++) { 309 auto pointerEvent = PointerEvent::Create(); 310 for (uint32_t finger = 0; finger < events.GetFingers(); finger++) { 311 pointerEvent->SetPointerId(finger); 312 PointerEvent::PointerItem pinterItem; 313 pinterItem.SetPointerId(finger); 314 pinterItem.SetDisplayX(events.At(finger, step).point_.px_); 315 pinterItem.SetDisplayY(events.At(finger, step).point_.py_); 316 switch (events.At(finger, step).stage_) { 317 case ActionStage::DOWN: 318 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_DOWN); 319 break; 320 case ActionStage::MOVE: 321 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_MOVE); 322 break; 323 case ActionStage::UP: 324 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_UP); 325 break; 326 } 327 pinterItem.SetPressed(events.At(finger, step).stage_ != ActionStage::UP); 328 pointerEvent->AddPointerItem(pinterItem); 329 pointerEvent->SetSourceType(PointerEvent::SOURCE_TYPE_TOUCHSCREEN); 330 DisplayManager &displayMgr = DisplayManager::GetInstance(); 331 pointerEvent->SetTargetDisplayId(displayMgr.GetDefaultDisplayId()); 332 InputManager::GetInstance()->SimulateInputEvent(pointerEvent); 333 if (events.At(finger, step).holdMs_ > 0) { 334 this_thread::sleep_for(chrono::milliseconds(events.At(finger, step).holdMs_)); 335 } 336 } 337 } 338 } 339 InjectKeyEventSequence(const vector<KeyEvent> & events) const340 void SysUiController::InjectKeyEventSequence(const vector<KeyEvent> &events) const 341 { 342 vector<int32_t> downKeys; 343 for (auto &event : events) { 344 if (event.stage_ == ActionStage::UP) { 345 auto iter = std::find(downKeys.begin(), downKeys.end(), event.code_); 346 if (iter == downKeys.end()) { 347 LOG_W("Cannot release a not-pressed key: %{public}d", event.code_); 348 continue; 349 } 350 downKeys.erase(iter); 351 auto keyEvent = OHOS::MMI::KeyEvent::Create(); 352 keyEvent->SetKeyCode(event.code_); 353 keyEvent->SetKeyAction(OHOS::MMI::KeyEvent::KEY_ACTION_UP); 354 OHOS::MMI::KeyEvent::KeyItem keyItem; 355 keyItem.SetKeyCode(event.code_); 356 keyItem.SetPressed(true); 357 keyEvent->AddKeyItem(keyItem); 358 InputManager::GetInstance()->SimulateInputEvent(keyEvent); 359 } else { 360 downKeys.push_back(event.code_); 361 auto keyEvent = OHOS::MMI::KeyEvent::Create(); 362 for (auto downKey : downKeys) { 363 keyEvent->SetKeyCode(downKey); 364 keyEvent->SetKeyAction(OHOS::MMI::KeyEvent::KEY_ACTION_DOWN); 365 OHOS::MMI::KeyEvent::KeyItem keyItem; 366 keyItem.SetKeyCode(downKey); 367 keyItem.SetPressed(true); 368 keyEvent->AddKeyItem(keyItem); 369 } 370 InputManager::GetInstance()->SimulateInputEvent(keyEvent); 371 if (event.holdMs_ > 0) { 372 this_thread::sleep_for(chrono::milliseconds(event.holdMs_)); 373 } 374 } 375 } 376 // check not released keys 377 for (auto downKey : downKeys) { 378 LOG_W("Key event sequence injections done with not-released key: %{public}d", downKey); 379 } 380 } 381 PutTextToClipboard(string_view text) const382 void SysUiController::PutTextToClipboard(string_view text) const {} 383 IsWorkable() const384 bool SysUiController::IsWorkable() const 385 { 386 return true; 387 } 388 GetCharKeyCode(char ch,int32_t & code,int32_t & ctrlCode) const389 bool SysUiController::GetCharKeyCode(char ch, int32_t &code, int32_t &ctrlCode) const 390 { 391 static const map<char, int32_t> keyMap = { 392 {'*', OHOS::MMI::KeyEvent::KEYCODE_STAR}, 393 {'#', OHOS::MMI::KeyEvent::KEYCODE_POUND}, 394 {',', OHOS::MMI::KeyEvent::KEYCODE_COMMA}, 395 {'.', OHOS::MMI::KeyEvent::KEYCODE_PERIOD}, 396 {'`', OHOS::MMI::KeyEvent::KEYCODE_GRAVE}, 397 {'-', OHOS::MMI::KeyEvent::KEYCODE_MINUS}, 398 {'=', OHOS::MMI::KeyEvent::KEYCODE_EQUALS}, 399 {'[', OHOS::MMI::KeyEvent::KEYCODE_LEFT_BRACKET}, 400 {']', OHOS::MMI::KeyEvent::KEYCODE_RIGHT_BRACKET}, 401 {'\\', OHOS::MMI::KeyEvent::KEYCODE_BACKSLASH}, 402 {';', OHOS::MMI::KeyEvent::KEYCODE_SEMICOLON}, 403 {'\'', OHOS::MMI::KeyEvent::KEYCODE_APOSTROPHE}, 404 {'/', OHOS::MMI::KeyEvent::KEYCODE_SLASH}, 405 {'@', OHOS::MMI::KeyEvent::KEYCODE_AT}, 406 {'+', OHOS::MMI::KeyEvent::KEYCODE_PLUS}, 407 {' ', OHOS::MMI::KeyEvent::KEYCODE_TAB}, 408 {' ', OHOS::MMI::KeyEvent::KEYCODE_SPACE}, 409 {0x7F, OHOS::MMI::KeyEvent::KEYCODE_DEL}}; 410 ctrlCode = KEYCODE_NONE; 411 if (ch >= 'a' && ch <= 'z') { 412 code = OHOS::MMI::KeyEvent::KEYCODE_A + static_cast<int32_t>(ch - 'a'); 413 } else if (ch >= 'A' && ch <= 'Z') { 414 ctrlCode = OHOS::MMI::KeyEvent::KEYCODE_SHIFT_LEFT; 415 code = OHOS::MMI::KeyEvent::KEYCODE_A + static_cast<int32_t>(ch - 'A'); 416 } else if (ch >= '0' && ch <= '9') { 417 code = OHOS::MMI::KeyEvent::KEYCODE_0 + static_cast<int32_t>(ch - '0'); 418 } else { 419 auto find = keyMap.find(ch); 420 if (find != keyMap.end()) { 421 code = find->second; 422 } else { 423 LOG_W("No keyCode found for char '%{public}c'", ch); 424 return false; 425 } 426 } 427 return true; 428 } 429 TakeScreenCap(string_view savePath,stringstream & errReceiver) const430 bool SysUiController::TakeScreenCap(string_view savePath, stringstream &errReceiver) const 431 { 432 DisplayManager &displayMgr = DisplayManager::GetInstance(); 433 // get PixelMap from DisplayManager API 434 shared_ptr<PixelMap> pixelMap = displayMgr.GetScreenshot(displayMgr.GetDefaultDisplayId()); 435 if (pixelMap == nullptr) { 436 errReceiver << "Failed to get display pixelMap"; 437 return false; 438 } 439 FILE *fp = fopen(savePath.data(), "wb"); 440 if (fp == nullptr) { 441 perror("File opening failed"); 442 errReceiver << "File opening failed: " << savePath; 443 return false; 444 } 445 png_structp pngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 446 if (pngStruct == nullptr) { 447 fclose(fp); 448 return false; 449 } 450 png_infop pngInfo = png_create_info_struct(pngStruct); 451 if (pngInfo == nullptr) { 452 fclose(fp); 453 png_destroy_write_struct(&pngStruct, nullptr); 454 return false; 455 } 456 png_init_io(pngStruct, fp); 457 auto width = static_cast<uint32_t>(pixelMap->GetWidth()); 458 auto height = static_cast<uint32_t>(pixelMap->GetHeight()); 459 auto data = pixelMap->GetPixels(); 460 auto stride = static_cast<uint32_t>(pixelMap->GetRowBytes()); 461 // set png header 462 static constexpr int bitmapDepth = 8; 463 png_set_IHDR(pngStruct, pngInfo, width, height, bitmapDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, 464 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 465 png_set_packing(pngStruct); // set packing info 466 png_write_info(pngStruct, pngInfo); // write to header 467 for (uint32_t column = 0; column < height; column++) { 468 png_write_row(pngStruct, data + (column * stride)); 469 } 470 // free/close 471 png_write_end(pngStruct, pngInfo); 472 png_destroy_write_struct(&pngStruct, &pngInfo); 473 (void)fclose(fp); 474 return true; 475 } 476 477 // UiEventMonitor instance. 478 static shared_ptr<UiEventMonitor> g_monitorInstance_; 479 ConnectToSysAbility()480 bool SysUiController::ConnectToSysAbility() 481 { 482 if (connected_) { 483 return true; 484 } 485 mutex mtx; 486 unique_lock<mutex> uLock(mtx); 487 condition_variable condition; 488 auto onConnectCallback = [&condition]() { 489 LOG_I("Success connect to AccessibilityUITestAbility"); 490 condition.notify_all(); 491 }; 492 auto onDisConnectCallback = [this]() { this->connected_ = false; }; 493 if (g_monitorInstance_ == nullptr) { 494 g_monitorInstance_ = make_shared<UiEventMonitor>(); 495 } 496 g_monitorInstance_->SetOnAbilityConnectCallback(onConnectCallback); 497 g_monitorInstance_->SetOnAbilityDisConnectCallback(onDisConnectCallback); 498 auto ability = AccessibilityUITestAbility::GetInstance(); 499 if (ability->RegisterAbilityListener(g_monitorInstance_) != RET_OK) { 500 LOG_E("Failed to register UiEventMonitor"); 501 return false; 502 } 503 auto ret = ability->Connect(); 504 switch (ret) { 505 case (RET_ERR_INVALID_PARAM): 506 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_INVALID_PARAM"); 507 return false; 508 case (RET_ERR_NULLPTR): 509 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_NULLPTR"); 510 return false; 511 case (RET_ERR_CONNECTION_EXIST): 512 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_CONNECTION_EXIST"); 513 return false; 514 case (RET_ERR_IPC_FAILED): 515 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_IPC_FAILED"); 516 return false; 517 case (RET_ERR_SAMGR): 518 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_SAMGR"); 519 return false; 520 default: 521 break; 522 } 523 const auto timeout = chrono::milliseconds(1000); 524 if (condition.wait_for(uLock, timeout) == cv_status::timeout) { 525 LOG_E("Wait connection to AccessibilityUITestAbility timed out"); 526 return false; 527 } 528 connected_ = true; 529 return true; 530 } 531 WaitForUiSteady(uint32_t idleThresholdMs,uint32_t timeoutMs) const532 bool SysUiController::WaitForUiSteady(uint32_t idleThresholdMs, uint32_t timeoutMs) const 533 { 534 return g_monitorInstance_->WaitEventIdle(idleThresholdMs, timeoutMs); 535 } 536 DisConnectFromSysAbility()537 void SysUiController::DisConnectFromSysAbility() 538 { 539 if (!connected_ || g_monitorInstance_ == nullptr) { 540 return; 541 } 542 connected_ = false; 543 mutex mtx; 544 unique_lock<mutex> uLock(mtx); 545 condition_variable condition; 546 auto onDisConnectCallback = [&condition]() { 547 LOG_I("Success disconnect from AccessibilityUITestAbility"); 548 condition.notify_all(); 549 }; 550 g_monitorInstance_->SetOnAbilityDisConnectCallback(onDisConnectCallback); 551 auto ability = AccessibilityUITestAbility::GetInstance(); 552 LOG_I("Start disconnect from AccessibilityUITestAbility"); 553 if (ability->Disconnect() != RET_OK) { 554 LOG_E("Failed to disconnect from AccessibilityUITestAbility"); 555 return; 556 } 557 const auto timeout = chrono::milliseconds(200); 558 if (condition.wait_for(uLock, timeout) == cv_status::timeout) { 559 LOG_E("Wait disconnection from AccessibilityUITestAbility timed out"); 560 return; 561 } 562 } 563 SetDisplayRotation(DisplayRotation rotation) const564 void SysUiController::SetDisplayRotation(DisplayRotation rotation) const 565 { 566 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 567 auto screenId = display->GetScreenId(); 568 ScreenManager &screenMgr = ScreenManager::GetInstance(); 569 auto screen = screenMgr.GetScreenById(screenId); 570 switch (rotation) { 571 case ROTATION_0 : 572 screen->SetOrientation(Orientation::VERTICAL); 573 break; 574 case ROTATION_90 : 575 screen->SetOrientation(Orientation::HORIZONTAL); 576 break; 577 case ROTATION_180 : 578 screen->SetOrientation(Orientation::REVERSE_VERTICAL); 579 break; 580 case ROTATION_270 : 581 screen->SetOrientation(Orientation::REVERSE_HORIZONTAL); 582 break; 583 default : 584 break; 585 } 586 } 587 GetDisplayRotation() const588 DisplayRotation SysUiController::GetDisplayRotation() const 589 { 590 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 591 auto rotation = (DisplayRotation)display->GetRotation(); 592 return rotation; 593 } 594 SetDisplayRotationEnabled(bool enabled) const595 void SysUiController::SetDisplayRotationEnabled(bool enabled) const 596 { 597 ScreenManager &screenMgr = ScreenManager::GetInstance(); 598 screenMgr.SetScreenRotationLocked(enabled); 599 } 600 GetDisplaySize() const601 Point SysUiController::GetDisplaySize() const 602 { 603 LOG_I("SysUiController::GetDisplaySize"); 604 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 605 auto width = display->GetWidth(); 606 auto height = display->GetHeight(); 607 Point result(width, height); 608 return result; 609 } 610 GetDisplayDensity() const611 Point SysUiController::GetDisplayDensity() const 612 { 613 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 614 auto rate = display->GetVirtualPixelRatio(); 615 Point displaySize = GetDisplaySize(); 616 Point result(displaySize.px_ * rate, displaySize.py_ * rate); 617 return result; 618 } 619 IsScreenOn() const620 bool SysUiController::IsScreenOn() const 621 { 622 DisplayManager &displayMgr = DisplayManager::GetInstance(); 623 auto displayId = displayMgr.GetDefaultDisplayId(); 624 auto state = displayMgr.GetDisplayState(displayId); 625 return (state != DisplayState::OFF); 626 } 627 } // namespace OHOS::uitest