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 <sys/mman.h> 25 #ifdef HIDUMPER_ENABLED 26 #include <iservice_registry.h> 27 #include <system_ability_load_callback_stub.h> 28 #include "idump_broker.h" 29 #include "dump_broker_proxy.h" 30 #include "system_ability_definition.h" 31 #endif 32 #include "accessibility_event_info.h" 33 #include "accessibility_ui_test_ability.h" 34 #include "ability_manager_client.h" 35 #include "display_manager.h" 36 #include "screen_manager.h" 37 #include "input_manager.h" 38 #include "png.h" 39 #include "wm_common.h" 40 #include "element_node_iterator_impl.h" 41 #include "system_ui_controller.h" 42 #include "test_server_client.h" 43 44 using namespace std; 45 using namespace chrono; 46 47 namespace OHOS::uitest { 48 using namespace std; 49 using namespace nlohmann; 50 using namespace OHOS::MMI; 51 using namespace OHOS::Accessibility; 52 using namespace OHOS::Rosen; 53 using namespace OHOS::Media; 54 using namespace OHOS::HiviewDFX; 55 using namespace OHOS; 56 57 class UiEventMonitor final : public AccessibleAbilityListener { 58 public: 59 virtual ~UiEventMonitor() override = default; 60 61 void OnAbilityConnected() override; 62 63 void OnAbilityDisconnected() override; 64 65 void OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo) override; 66 67 void SetOnAbilityConnectCallback(function<void()> onConnectCb); 68 69 void SetOnAbilityDisConnectCallback(function<void()> onDisConnectCb); 70 OnKeyPressEvent(const shared_ptr<MMI::KeyEvent> & keyEvent)71 bool OnKeyPressEvent(const shared_ptr<MMI::KeyEvent> &keyEvent) override 72 { 73 return false; 74 } 75 76 uint64_t GetLastEventMillis(); 77 78 bool WaitEventIdle(uint32_t idleThresholdMs, uint32_t timeoutMs); 79 80 void WaitScrollCompelete(); 81 82 void RegisterUiEventListener(shared_ptr<UiEventListener> listerner); 83 84 private: 85 function<void()> onConnectCallback_ = nullptr; 86 function<void()> onDisConnectCallback_ = nullptr; 87 atomic<uint64_t> lastEventMillis_ = 0; 88 atomic<uint64_t> lastScrollBeginEventMillis_ = 0; 89 atomic<bool> scrollCompelete_ = true; 90 vector<shared_ptr<UiEventListener>> listeners_; 91 }; 92 93 struct EventSpec { 94 std::string_view componentTyep; 95 int32_t eventType; 96 std::string_view event; 97 }; 98 99 const std::map<char, int32_t> SingleKeySymbalMap = { 100 {' ', OHOS::MMI::KeyEvent::KEYCODE_SPACE}, 101 {'`', OHOS::MMI::KeyEvent::KEYCODE_GRAVE}, 102 {'[', OHOS::MMI::KeyEvent::KEYCODE_LEFT_BRACKET}, 103 {']', OHOS::MMI::KeyEvent::KEYCODE_RIGHT_BRACKET}, 104 {'\\', OHOS::MMI::KeyEvent::KEYCODE_BACKSLASH}, 105 {',', OHOS::MMI::KeyEvent::KEYCODE_COMMA}, 106 {';', OHOS::MMI::KeyEvent::KEYCODE_SEMICOLON}, 107 {'\'', OHOS::MMI::KeyEvent::KEYCODE_APOSTROPHE}, 108 {'/', OHOS::MMI::KeyEvent::KEYCODE_SLASH}, 109 {'*', OHOS::MMI::KeyEvent::KEYCODE_NUMPAD_MULTIPLY}, 110 {'-', OHOS::MMI::KeyEvent::KEYCODE_MINUS}, 111 {'.', OHOS::MMI::KeyEvent::KEYCODE_PERIOD}, 112 {'=', OHOS::MMI::KeyEvent::KEYCODE_EQUALS} 113 }; 114 115 const std::map<char, int32_t> MultiKeySymbalMap = { 116 {'~', OHOS::MMI::KeyEvent::KEYCODE_GRAVE}, 117 {'!', OHOS::MMI::KeyEvent::KEYCODE_1}, 118 {'@', OHOS::MMI::KeyEvent::KEYCODE_2}, 119 {'#', OHOS::MMI::KeyEvent::KEYCODE_3}, 120 {'$', OHOS::MMI::KeyEvent::KEYCODE_4}, 121 {'%', OHOS::MMI::KeyEvent::KEYCODE_5}, 122 {'^', OHOS::MMI::KeyEvent::KEYCODE_6}, 123 {'&', OHOS::MMI::KeyEvent::KEYCODE_7}, 124 {'(', OHOS::MMI::KeyEvent::KEYCODE_9}, 125 {')', OHOS::MMI::KeyEvent::KEYCODE_0}, 126 {'+', OHOS::MMI::KeyEvent::KEYCODE_EQUALS}, 127 {'_', OHOS::MMI::KeyEvent::KEYCODE_MINUS}, 128 {':', OHOS::MMI::KeyEvent::KEYCODE_SEMICOLON}, 129 {'"', OHOS::MMI::KeyEvent::KEYCODE_APOSTROPHE}, 130 {'<', OHOS::MMI::KeyEvent::KEYCODE_COMMA}, 131 {'>', OHOS::MMI::KeyEvent::KEYCODE_PERIOD}, 132 {'?', OHOS::MMI::KeyEvent::KEYCODE_SLASH}, 133 {'{', OHOS::MMI::KeyEvent::KEYCODE_LEFT_BRACKET}, 134 {'}', OHOS::MMI::KeyEvent::KEYCODE_RIGHT_BRACKET}, 135 {'|', OHOS::MMI::KeyEvent::KEYCODE_BACKSLASH} 136 }; 137 138 static constexpr EventSpec WATCHED_EVENTS[] = { 139 {"Toast", WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_SUBTREE, "toastShow"}, 140 {"AlertDialog", WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_SUBTREE, "dialogShow"} 141 }; 142 GetWatchedEvent(const AccessibilityEventInfo & eventInfo)143 static std::string GetWatchedEvent(const AccessibilityEventInfo &eventInfo) 144 { 145 auto eventCounts = sizeof(WATCHED_EVENTS) / sizeof(EventSpec); 146 for (unsigned long index = 0; index < eventCounts; index++) { 147 if (WATCHED_EVENTS[index].componentTyep == eventInfo.GetComponentType() && 148 WATCHED_EVENTS[index].eventType == eventInfo.GetWindowContentChangeTypes()) { 149 LOG_W("Capture event: %{public}s", WATCHED_EVENTS[index].event.data()); 150 return string(WATCHED_EVENTS[index].event); 151 } 152 } 153 return "undefine"; 154 } 155 156 // UiEventMonitor instance. 157 static shared_ptr<UiEventMonitor> g_monitorInstance_ = make_shared<UiEventMonitor>(); 158 SetOnAbilityConnectCallback(function<void ()> onConnectCb)159 void UiEventMonitor::SetOnAbilityConnectCallback(function<void()> onConnectCb) 160 { 161 onConnectCallback_ = std::move(onConnectCb); 162 } 163 SetOnAbilityDisConnectCallback(function<void ()> onDisConnectCb)164 void UiEventMonitor::SetOnAbilityDisConnectCallback(function<void()> onDisConnectCb) 165 { 166 onDisConnectCallback_ = std::move(onDisConnectCb); 167 } 168 OnAbilityConnected()169 void UiEventMonitor::OnAbilityConnected() 170 { 171 if (onConnectCallback_ != nullptr) { 172 onConnectCallback_(); 173 } 174 } 175 OnAbilityDisconnected()176 void UiEventMonitor::OnAbilityDisconnected() 177 { 178 if (onDisConnectCallback_ != nullptr) { 179 onDisConnectCallback_(); 180 } 181 } 182 183 // the monitored events 184 static const std::set<uint32_t> EVENT_MASK = { 185 EventType::TYPE_VIEW_TEXT_UPDATE_EVENT, 186 EventType::TYPE_PAGE_STATE_UPDATE, 187 EventType::TYPE_PAGE_CONTENT_UPDATE, 188 EventType::TYPE_VIEW_SCROLLED_EVENT, 189 EventType::TYPE_WINDOW_UPDATE 190 }; 191 RegisterUiEventListener(std::shared_ptr<UiEventListener> listerner)192 void UiEventMonitor::RegisterUiEventListener(std::shared_ptr<UiEventListener> listerner) 193 { 194 listeners_.emplace_back(listerner); 195 } 196 OnAccessibilityEvent(const AccessibilityEventInfo & eventInfo)197 void UiEventMonitor::OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo) 198 { 199 auto eventType = eventInfo.GetEventType(); 200 LOG_D("OnEvent:0x%{public}x", eventType); 201 auto capturedEvent = GetWatchedEvent(eventInfo); 202 if (eventType == Accessibility::EventType::TYPE_VIEW_SCROLLED_START) { 203 LOG_I("Capture scroll begin"); 204 scrollCompelete_.store(false); 205 lastScrollBeginEventMillis_.store(GetCurrentMillisecond()); 206 } 207 if (eventType == Accessibility::EventType::TYPE_VIEW_SCROLLED_EVENT) { 208 LOG_I("Capture scroll end"); 209 scrollCompelete_.store(true); 210 } 211 if (capturedEvent != "undefine") { 212 auto bundleName = eventInfo.GetBundleName(); 213 auto contentList = eventInfo.GetContentList(); 214 auto text = !contentList.empty() ? contentList[0] : ""; 215 auto type = eventInfo.GetComponentType(); 216 UiEventSourceInfo uiEventSourceInfo = {bundleName, text, type}; 217 for (auto &listener : listeners_) { 218 listener->OnEvent(capturedEvent, uiEventSourceInfo); 219 } 220 } 221 if (EVENT_MASK.find(eventInfo.GetEventType()) != EVENT_MASK.end()) { 222 lastEventMillis_.store(GetCurrentMillisecond()); 223 } 224 } 225 GetLastEventMillis()226 uint64_t UiEventMonitor::GetLastEventMillis() 227 { 228 if (lastEventMillis_.load() <= 0) { 229 lastEventMillis_.store(GetCurrentMillisecond()); 230 } 231 return lastEventMillis_.load(); 232 } 233 WaitScrollCompelete()234 void UiEventMonitor::WaitScrollCompelete() 235 { 236 if (scrollCompelete_.load()) { 237 return; 238 } 239 auto currentMs = GetCurrentMillisecond(); 240 if (lastScrollBeginEventMillis_.load() <= 0) { 241 lastScrollBeginEventMillis_.store(currentMs); 242 } 243 const auto idleThresholdMs = 10000; 244 static constexpr auto sliceMs = 10; 245 while (currentMs - lastScrollBeginEventMillis_.load() < idleThresholdMs) { 246 if (scrollCompelete_.load()) { 247 return; 248 } 249 this_thread::sleep_for(chrono::milliseconds(sliceMs)); 250 currentMs = GetCurrentMillisecond(); 251 } 252 LOG_E("wait for scrollEnd event timeout."); 253 scrollCompelete_.store(true); 254 return; 255 } 256 WaitEventIdle(uint32_t idleThresholdMs,uint32_t timeoutMs)257 bool UiEventMonitor::WaitEventIdle(uint32_t idleThresholdMs, uint32_t timeoutMs) 258 { 259 const auto currentMs = GetCurrentMillisecond(); 260 if (lastEventMillis_.load() <= 0) { 261 lastEventMillis_.store(currentMs); 262 } 263 if (currentMs - lastEventMillis_.load() >= idleThresholdMs) { 264 return true; 265 } 266 static constexpr auto sliceMs = 10; 267 this_thread::sleep_for(chrono::milliseconds(sliceMs)); 268 if (timeoutMs <= sliceMs) { 269 return false; 270 } 271 return WaitEventIdle(idleThresholdMs, timeoutMs - sliceMs); 272 } 273 SysUiController()274 SysUiController::SysUiController() : UiController() {} 275 ~SysUiController()276 SysUiController::~SysUiController() 277 { 278 DisConnectFromSysAbility(); 279 } 280 Initialize(ApiCallErr & error)281 bool SysUiController::Initialize(ApiCallErr &error) 282 { 283 return this->ConnectToSysAbility(error); 284 } 285 GetFoldArea()286 static Rect GetFoldArea() 287 { 288 auto foldCreaseRegion = DisplayManager::GetInstance().GetCurrentFoldCreaseRegion(); 289 auto areas = foldCreaseRegion->GetCreaseRects(); 290 if (areas.size() == 1) { 291 auto foldArea = *areas.begin(); 292 LOG_D("foldArea, left: %{public}d, top: %{public}d, width: %{public}d, height: %{public}d", 293 foldArea.posX_, foldArea.posY_, foldArea.width_, foldArea.height_); 294 return Rect(foldArea.posX_, foldArea.posX_ + foldArea.width_, 295 foldArea.posY_, foldArea.posY_ + foldArea.height_); 296 } else { 297 LOG_E("Invalid display info."); 298 return Rect(0, 0, 0, 0); 299 } 300 } 301 GetVisibleRect(Rect screenBounds,AccessibilityWindowInfo & node)302 static Rect GetVisibleRect(Rect screenBounds, AccessibilityWindowInfo &node) 303 { 304 auto nodeBounds = node.GetRectInScreen(); 305 auto leftX = nodeBounds.GetLeftTopXScreenPostion(); 306 auto topY = nodeBounds.GetLeftTopYScreenPostion(); 307 auto rightX = nodeBounds.GetRightBottomXScreenPostion(); 308 auto bottomY = nodeBounds.GetRightBottomYScreenPostion(); 309 if (node.GetDisplayId() == VIRTUAL_DISPLAY_ID) { 310 auto foldArea = GetFoldArea(); 311 topY += foldArea.bottom_; 312 bottomY += foldArea.bottom_; 313 } 314 Rect newBounds((leftX < screenBounds.left_) ? screenBounds.left_ : leftX, 315 (rightX > screenBounds.right_) ? screenBounds.right_ : rightX, 316 (topY < screenBounds.top_) ? screenBounds.top_ : topY, 317 (bottomY > screenBounds.bottom_) ? screenBounds.bottom_ : bottomY); 318 return newBounds; 319 } 320 InflateWindowInfo(AccessibilityWindowInfo & node,Window & info)321 static void InflateWindowInfo(AccessibilityWindowInfo& node, Window& info) 322 { 323 info.focused_ = node.IsFocused(); 324 info.actived_ = node.IsActive(); 325 info.decoratorEnabled_ = node.IsDecorEnable(); 326 // get bundle name by root node 327 AccessibilityElementInfo element; 328 LOG_D("Start Get Bundle Name by WindowId %{public}d", node.GetWindowId()); 329 if (AccessibilityUITestAbility::GetInstance()->GetRootByWindow(node, element) != RET_OK) { 330 LOG_E("Failed Get Bundle Name by WindowId %{public}d", node.GetWindowId()); 331 } else { 332 std::string app = element.GetBundleName(); 333 LOG_I("End Get Bundle Name by WindowId %{public}d, app is %{public}s", node.GetWindowId(), app.data()); 334 info.bundleName_ = app; 335 const auto foreAbility = AAFwk::AbilityManagerClient::GetInstance()->GetTopAbility(); 336 info.abilityName_ = (app == foreAbility.GetBundleName()) ? foreAbility.GetAbilityName() : ""; 337 info.pagePath_ = (app == foreAbility.GetBundleName()) ? element.GetPagePath() : ""; 338 } 339 info.mode_ = WindowMode::UNKNOWN; 340 auto touchAreas = node.GetTouchHotAreas(); 341 for (auto area : touchAreas) { 342 Rect rect { area.GetLeftTopXScreenPostion(), area.GetRightBottomXScreenPostion(), 343 area.GetLeftTopYScreenPostion(), area.GetRightBottomYScreenPostion() }; 344 info.touchHotAreas_.push_back(rect); 345 } 346 const auto origMode = static_cast<OHOS::Rosen::WindowMode>(node.GetWindowMode()); 347 switch (origMode) { 348 case OHOS::Rosen::WindowMode::WINDOW_MODE_FULLSCREEN: 349 info.mode_ = WindowMode::FULLSCREEN; 350 break; 351 case OHOS::Rosen::WindowMode::WINDOW_MODE_SPLIT_PRIMARY: 352 info.mode_ = WindowMode::SPLIT_PRIMARY; 353 break; 354 case OHOS::Rosen::WindowMode::WINDOW_MODE_SPLIT_SECONDARY: 355 info.mode_ = WindowMode::SPLIT_SECONDARY; 356 break; 357 case OHOS::Rosen::WindowMode::WINDOW_MODE_FLOATING: 358 info.mode_ = WindowMode::FLOATING; 359 break; 360 case OHOS::Rosen::WindowMode::WINDOW_MODE_PIP: 361 info.mode_ = WindowMode::PIP; 362 break; 363 default: 364 info.mode_ = WindowMode::UNKNOWN; 365 break; 366 } 367 } 368 GetAamsWindowInfos(vector<AccessibilityWindowInfo> & windows,int32_t displayId)369 static bool GetAamsWindowInfos(vector<AccessibilityWindowInfo> &windows, int32_t displayId) 370 { 371 LOG_D("Get Window root info in display %{public}d", displayId); 372 auto ability = AccessibilityUITestAbility::GetInstance(); 373 g_monitorInstance_->WaitScrollCompelete(); 374 auto ret = ability->GetWindows(displayId, windows); 375 if (ret != RET_OK) { 376 LOG_W("GetWindows in display %{public}d from AccessibilityUITestAbility failed, ret: %{public}d", 377 displayId, ret); 378 return false; 379 } 380 auto hasVirtual = DisplayManager::GetInstance().GetDisplayById(VIRTUAL_DISPLAY_ID) != nullptr; 381 if (hasVirtual && displayId == 0) { 382 vector<AccessibilityWindowInfo> windowsInVirtual; 383 auto ret1 = ability->GetWindows(VIRTUAL_DISPLAY_ID, windowsInVirtual); 384 LOG_D("GetWindows in display 999 from AccessibilityUITestAbility, ret: %{public}d", ret1); 385 for (auto &win : windowsInVirtual) { 386 windows.emplace_back(win); 387 } 388 } 389 if (windows.empty()) { 390 LOG_E("Get Windows in display %{public}d failed", displayId); 391 return false; 392 } 393 sort(windows.begin(), windows.end(), [](auto &w1, auto &w2) -> bool { 394 return w1.GetWindowLayer() > w2.GetWindowLayer(); 395 }); 396 LOG_D("End Get Window root info"); 397 return true; 398 } 399 UpdateWindowAttrs(Window & win,std::vector<Rect> & overplays)400 static void UpdateWindowAttrs(Window &win, std::vector<Rect> &overplays) 401 { 402 for (const auto &overWin : overplays) { 403 Rect intersectionRect{0, 0, 0, 0}; 404 if (RectAlgorithm::ComputeIntersection(win.bounds_, overWin, intersectionRect)) { 405 win.invisibleBoundsVec_.emplace_back(overWin); 406 } 407 } 408 RectAlgorithm::ComputeMaxVisibleRegion(win.bounds_, overplays, win.visibleBounds_); 409 if (win.touchHotAreas_.empty()) { 410 overplays.emplace_back(win.bounds_); 411 } else { 412 std::string touchAreaInfo; 413 for (auto rect : win.touchHotAreas_) { 414 touchAreaInfo += rect.Describe() + " "; 415 overplays.emplace_back(rect); 416 } 417 LOG_I("window %{public}d touchArea: %{public}s", win.id_, touchAreaInfo.c_str()); 418 } 419 if (win.displayId_ == VIRTUAL_DISPLAY_ID) { 420 win.offset_ = Point(0, GetFoldArea().bottom_); 421 } 422 } 423 GetUiWindows(std::map<int32_t,vector<Window>> & out,int32_t targetDisplay)424 void SysUiController::GetUiWindows(std::map<int32_t, vector<Window>> &out, int32_t targetDisplay) 425 { 426 std::lock_guard<std::mutex> dumpLocker(dumpMtx); // disallow concurrent dumpUi 427 ApiCallErr error = ApiCallErr(NO_ERROR); 428 if (!connected_ && !ConnectToSysAbility(error)) { 429 LOG_E("%{public}s", error.message_.c_str()); 430 return; 431 } 432 DisplayManager &dpm = DisplayManager::GetInstance(); 433 auto displayIds = dpm.GetAllDisplayIds(); 434 for (auto displayId : displayIds) { 435 if ((targetDisplay != -1 && targetDisplay != static_cast<int32_t>(displayId)) || 436 displayId == VIRTUAL_DISPLAY_ID) { 437 continue; 438 } 439 vector<AccessibilityWindowInfo> windows; 440 if (!GetAamsWindowInfos(windows, displayId)) { 441 continue; 442 } 443 auto screenSize = GetDisplaySize(displayId); 444 auto screenRect = Rect(0, screenSize.px_, 0, screenSize.py_); 445 std::vector<Window> winInfos; 446 std::vector<Rect> overplays; 447 // window wrapper 448 for (auto &win : windows) { 449 Rect winRectInScreen = GetVisibleRect(screenRect, win); 450 Rect visibleArea = winRectInScreen; 451 if (!RectAlgorithm::ComputeMaxVisibleRegion(winRectInScreen, overplays, visibleArea)) { 452 LOG_I("window is covered, windowId : %{public}d, layer is %{public}d", win.GetWindowId(), 453 win.GetWindowLayer()); 454 continue; 455 } 456 LOG_I("window is visible, windowId: " 457 "%{public}d, active: %{public}d, focus: %{public}d, layer: %{public}d", 458 win.GetWindowId(), win.IsActive(), win.IsFocused(), win.GetWindowLayer()); 459 Window winWrapper{win.GetWindowId()}; 460 InflateWindowInfo(win, winWrapper); 461 winWrapper.bounds_ = winRectInScreen; 462 winWrapper.displayId_ = win.GetDisplayId(); 463 UpdateWindowAttrs(winWrapper, overplays); 464 winWrapper.displayId_ = displayId; 465 winInfos.emplace_back(move(winWrapper)); 466 } 467 out.insert(make_pair(displayId, move(winInfos))); 468 } 469 } 470 GetWidgetsInWindow(const Window & winInfo,unique_ptr<ElementNodeIterator> & elementIterator,AamsWorkMode mode)471 bool SysUiController::GetWidgetsInWindow(const Window &winInfo, unique_ptr<ElementNodeIterator> &elementIterator, 472 AamsWorkMode mode) 473 { 474 std::lock_guard<std::mutex> dumpLocker(dumpMtx); // disallow concurrent dumpUi 475 if (!connected_) { 476 LOG_W("Connect to AccessibilityUITestAbility failed"); 477 return false; 478 } 479 std::vector<AccessibilityElementInfo> elementInfos; 480 AccessibilityWindowInfo window; 481 LOG_D("Get Window by WindowId %{public}d", winInfo.id_); 482 if (AccessibilityUITestAbility::GetInstance()->GetWindow(winInfo.id_, window) != RET_OK) { 483 LOG_E("GetWindowInfo failed, windowId: %{public}d", winInfo.id_); 484 return false; 485 } 486 LOG_D("Start Get nodes from window by WindowId %{public}d", winInfo.id_); 487 auto ret = RET_ERR_FAILED; 488 auto ability = AccessibilityUITestAbility::GetInstance(); 489 if (mode == AamsWorkMode::FASTGETNODE) { 490 LOG_D("GetRootByWindowBatch in reduced mode"); 491 ret = ability->GetRootByWindowBatch(window, elementInfos, false, true); 492 } else { 493 ret = ability->GetRootByWindowBatch(window, elementInfos); 494 } 495 if (ret != RET_OK) { 496 LOG_E("GetRootByWindowBatch failed, windowId: %{public}d", winInfo.id_); 497 return false; 498 } else { 499 LOG_I("End Get nodes from window by WindowId %{public}d, node size is %{public}zu, appId: %{public}s", 500 winInfo.id_, elementInfos.size(), winInfo.bundleName_.data()); 501 elementIterator = std::make_unique<ElementNodeIteratorImpl>(elementInfos); 502 } 503 return true; 504 } 505 GetValidDisplayId(int32_t id) const506 int32_t SysUiController::GetValidDisplayId(int32_t id) const 507 { 508 if (id == UNASSIGNED) { 509 id = DisplayManager::GetInstance().GetDefaultDisplayId(); 510 } 511 return id; 512 } 513 SetItemByType(PointerEvent::PointerItem & pinterItem,const PointerMatrix & events)514 static void SetItemByType(PointerEvent::PointerItem &pinterItem, const PointerMatrix &events) 515 { 516 switch (events.GetToolType()) { 517 case PointerEvent::TOOL_TYPE_FINGER: 518 pinterItem.SetToolType(PointerEvent::TOOL_TYPE_FINGER); 519 break; 520 case PointerEvent::TOOL_TYPE_PEN: 521 pinterItem.SetToolType(PointerEvent::TOOL_TYPE_PEN); 522 pinterItem.SetPressure(events.GetTouchPressure()); 523 break; 524 default: 525 return; 526 } 527 } 528 AddPointerItems(PointerEvent & event,const vector<pair<bool,Point>> & fingerStatus,uint32_t currentFinger,const PointerMatrix & events)529 static void AddPointerItems(PointerEvent &event, const vector<pair<bool, Point>> &fingerStatus, 530 uint32_t currentFinger, const PointerMatrix &events) 531 { 532 PointerEvent::PointerItem pinterItem1; 533 pinterItem1.SetPointerId(currentFinger); 534 pinterItem1.SetOriginPointerId(currentFinger); 535 pinterItem1.SetDisplayX(fingerStatus[currentFinger].second.px_); 536 pinterItem1.SetDisplayY(fingerStatus[currentFinger].second.py_); 537 pinterItem1.SetRawDisplayX(fingerStatus[currentFinger].second.px_); 538 pinterItem1.SetRawDisplayY(fingerStatus[currentFinger].second.py_); 539 pinterItem1.SetPressed(fingerStatus[currentFinger].first); 540 SetItemByType(pinterItem1, events); 541 event.UpdatePointerItem(currentFinger, pinterItem1); 542 LOG_D("Add touchItem, finger:%{public}d, pressed:%{public}d, location:%{public}d, %{public}d", 543 currentFinger, fingerStatus[currentFinger].first, fingerStatus[currentFinger].second.px_, 544 fingerStatus[currentFinger].second.py_); 545 // update pinterItem of other fingers which in pressed state. 546 for (uint32_t index = 0; index < fingerStatus.size(); index++) { 547 if (index == currentFinger) { 548 continue; 549 } 550 if (fingerStatus[index].first) { 551 PointerEvent::PointerItem pinterItem; 552 pinterItem.SetPointerId(index); 553 pinterItem.SetOriginPointerId(index); 554 pinterItem.SetDisplayX(fingerStatus[index].second.px_); 555 pinterItem.SetDisplayY(fingerStatus[index].second.py_); 556 pinterItem.SetRawDisplayX(fingerStatus[index].second.px_); 557 pinterItem.SetRawDisplayY(fingerStatus[index].second.py_); 558 pinterItem.SetPressed(true); 559 SetItemByType(pinterItem, events); 560 event.UpdatePointerItem(index, pinterItem); 561 LOG_D("Add touchItem, finger:%{public}d, pressed:%{public}d, location:%{public}d, %{public}d", 562 index, fingerStatus[index].first, fingerStatus[index].second.px_, 563 fingerStatus[index].second.py_); 564 } 565 } 566 } 567 InjectTouchEventSequence(const PointerMatrix & events) const568 void SysUiController::InjectTouchEventSequence(const PointerMatrix &events) const 569 { 570 // fingerStatus stores the press status and coordinates of each finger. 571 vector<pair<bool, Point>> fingerStatus(events.GetFingers(), make_pair(false, Point(0,0))); 572 for (uint32_t step = 0; step < events.GetSteps(); step++) { 573 for (uint32_t finger = 0; finger < events.GetFingers(); finger++) { 574 auto pointerEvent = PointerEvent::Create(); 575 if (pointerEvent == nullptr) { 576 LOG_E("Creat PointerEvent failed."); 577 return; 578 } 579 bool isPressed = (events.At(finger, step).stage_ == ActionStage::DOWN) || 580 (events.At(finger, step).stage_ == ActionStage::MOVE); 581 fingerStatus[finger] = make_pair(isPressed, events.At(finger, step).point_); 582 pointerEvent->SetPointerId(finger); 583 switch (events.At(finger, step).stage_) { 584 case ActionStage::DOWN: 585 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_DOWN); 586 break; 587 case ActionStage::MOVE: 588 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_MOVE); 589 break; 590 case ActionStage::UP: 591 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_UP); 592 break; 593 case ActionStage::PROXIMITY_IN: 594 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_PROXIMITY_IN); 595 break; 596 case ActionStage::PROXIMITY_OUT: 597 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_PROXIMITY_OUT); 598 break; 599 default: 600 return; 601 } 602 AddPointerItems(*pointerEvent, fingerStatus, finger, events); 603 pointerEvent->SetSourceType(PointerEvent::SOURCE_TYPE_TOUCHSCREEN); 604 auto displayId = GetValidDisplayId(events.At(finger, step).point_.displayId_); 605 pointerEvent->SetTargetDisplayId(displayId); 606 InputManager::GetInstance()->SimulateInputEvent(pointerEvent, false); 607 LOG_D("Inject touchEvent to display : %{public}d", displayId); 608 if (events.At(finger, step).holdMs_ > 0) { 609 this_thread::sleep_for(chrono::milliseconds(events.At(finger, step).holdMs_)); 610 } 611 } 612 } 613 } 614 SetMousePointerItemAttr(const MouseEvent & event,PointerEvent::PointerItem & item)615 static void SetMousePointerItemAttr(const MouseEvent &event, PointerEvent::PointerItem &item) 616 { 617 item.SetPointerId(0); 618 item.SetOriginPointerId(0); 619 item.SetToolType(PointerEvent::TOOL_TYPE_MOUSE); 620 item.SetDisplayX(event.point_.px_); 621 item.SetDisplayY(event.point_.py_); 622 item.SetRawDisplayX(event.point_.px_); 623 item.SetRawDisplayY(event.point_.py_); 624 item.SetPressed(false); 625 item.SetDownTime(0); 626 LOG_D("Inject mouseEvent, pressed:%{public}d, location:%{public}d, %{public}d", 627 event.stage_ == ActionStage::DOWN, event.point_.px_, event.point_.py_); 628 } 629 SetMousePointerEventAttr(shared_ptr<PointerEvent> pointerEvent,const MouseEvent & event)630 static void SetMousePointerEventAttr(shared_ptr<PointerEvent> pointerEvent, const MouseEvent &event) 631 { 632 pointerEvent->SetSourceType(PointerEvent::SOURCE_TYPE_MOUSE); 633 pointerEvent->SetPointerId(0); 634 if (event.button_ != MouseButton::BUTTON_NONE) { 635 pointerEvent->SetButtonId(event.button_); 636 if ((event.stage_ == ActionStage::DOWN || event.stage_ == ActionStage::MOVE)) { 637 pointerEvent->SetButtonPressed(event.button_); 638 } else if (event.stage_ == ActionStage::UP) { 639 pointerEvent->DeleteReleaseButton(event.button_); 640 } 641 } 642 } 643 InjectMouseEvent(const MouseEvent & event) const644 void SysUiController::InjectMouseEvent(const MouseEvent &event) const 645 { 646 auto pointerEvent = PointerEvent::Create(); 647 if (pointerEvent == nullptr) { 648 return; 649 } 650 PointerEvent::PointerItem item; 651 SetMousePointerEventAttr(pointerEvent, event); 652 constexpr double axialValue = 15; 653 static bool flag = true; 654 auto injectAxialValue = axialValue; 655 switch (event.stage_) { 656 case ActionStage::DOWN: 657 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN); 658 item.SetPressed(true); 659 break; 660 case ActionStage::MOVE: 661 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_MOVE); 662 break; 663 case ActionStage::UP: 664 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_BUTTON_UP); 665 break; 666 case ActionStage::AXIS_UP: 667 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_BEGIN); 668 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, -axialValue); 669 flag = false; 670 break; 671 case ActionStage::AXIS_DOWN: 672 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_BEGIN); 673 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, axialValue); 674 flag = true; 675 break; 676 case ActionStage::AXIS_STOP: 677 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_END); 678 injectAxialValue = flag ? axialValue : -axialValue; 679 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, injectAxialValue); 680 break; 681 default: 682 return; 683 } 684 SetMousePointerItemAttr(event, item); 685 pointerEvent->AddPointerItem(item); 686 auto displayId = GetValidDisplayId(event.point_.displayId_); 687 pointerEvent->SetTargetDisplayId(displayId); 688 if (!downKeys_.empty()) { 689 pointerEvent->SetPressedKeys(downKeys_); 690 } 691 InputManager::GetInstance()->SimulateInputEvent(pointerEvent, false); 692 LOG_D("Inject mouseEvent to display : %{public}d", displayId); 693 this_thread::sleep_for(chrono::milliseconds(event.holdMs_)); 694 } 695 InjectMouseEventSequence(const vector<MouseEvent> & events) const696 void SysUiController::InjectMouseEventSequence(const vector<MouseEvent> &events) const 697 { 698 for (auto &event : events) { 699 auto keyEvents = event.keyEvents_; 700 if (!keyEvents.empty() && keyEvents.front().stage_ == ActionStage::DOWN) { 701 InjectKeyEventSequence(keyEvents); 702 InjectMouseEvent(event); 703 } else { 704 InjectMouseEvent(event); 705 InjectKeyEventSequence(keyEvents); 706 } 707 } 708 } 709 InjectKeyEventSequence(const vector<KeyEvent> & events) const710 void SysUiController::InjectKeyEventSequence(const vector<KeyEvent> &events) const 711 { 712 for (auto &event : events) { 713 if (event.code_ == KEYCODE_NONE) { 714 continue; 715 } 716 auto keyEvent = OHOS::MMI::KeyEvent::Create(); 717 if (keyEvent == nullptr) { 718 LOG_E("Creat KeyEvent failed."); 719 return; 720 } 721 if (event.stage_ == ActionStage::UP) { 722 auto iter = std::find(downKeys_.begin(), downKeys_.end(), event.code_); 723 if (iter == downKeys_.end()) { 724 LOG_W("Cannot release a not-pressed key: %{public}d", event.code_); 725 continue; 726 } 727 downKeys_.erase(iter); 728 keyEvent->SetKeyCode(event.code_); 729 keyEvent->SetKeyAction(OHOS::MMI::KeyEvent::KEY_ACTION_UP); 730 OHOS::MMI::KeyEvent::KeyItem keyItem; 731 keyItem.SetKeyCode(event.code_); 732 keyItem.SetPressed(false); 733 keyEvent->AddKeyItem(keyItem); 734 InputManager::GetInstance()->SimulateInputEvent(keyEvent); 735 LOG_D("Inject keyEvent up, keycode:%{public}d", event.code_); 736 } else { 737 downKeys_.push_back(event.code_); 738 for (auto downKey : downKeys_) { 739 keyEvent->SetKeyCode(downKey); 740 keyEvent->SetKeyAction(OHOS::MMI::KeyEvent::KEY_ACTION_DOWN); 741 OHOS::MMI::KeyEvent::KeyItem keyItem; 742 keyItem.SetKeyCode(downKey); 743 keyItem.SetPressed(true); 744 keyEvent->AddKeyItem(keyItem); 745 } 746 InputManager::GetInstance()->SimulateInputEvent(keyEvent); 747 LOG_D("Inject keyEvent down, keycode:%{public}d", event.code_); 748 if (event.holdMs_ > 0) { 749 this_thread::sleep_for(chrono::milliseconds(event.holdMs_)); 750 } 751 } 752 } 753 // check not released keys 754 for (auto downKey : downKeys_) { 755 LOG_W("Key event sequence injections done with not-released key: %{public}d", downKey); 756 } 757 } 758 IsTouchPadExist() const759 bool SysUiController::IsTouchPadExist() const 760 { 761 std::vector<int32_t> inputDeviceIdList; 762 auto getDeviceIdsCallback = [&inputDeviceIdList](std::vector<int32_t>& deviceIds) { 763 inputDeviceIdList = deviceIds; 764 }; 765 int32_t ret1 = InputManager::GetInstance()->GetDeviceIds(getDeviceIdsCallback); 766 if (ret1 != RET_OK) { 767 LOG_E("Get device ids failed"); 768 return false; 769 } 770 const int32_t touchPadTag = 1 << 3; 771 for (auto inputDeviceId : inputDeviceIdList) { 772 std::shared_ptr<MMI::InputDevice> inputDevice; 773 auto getDeviceCallback = [&inputDevice](std::shared_ptr<MMI::InputDevice> device) { 774 inputDevice = device; 775 }; 776 int32_t ret2 = MMI::InputManager::GetInstance()->GetDevice(inputDeviceId, getDeviceCallback); 777 if (ret2 != RET_OK || inputDevice == nullptr) { 778 LOG_E("Get device failed"); 779 continue; 780 } 781 if (inputDevice->GetType() & touchPadTag) { 782 return true; 783 } 784 } 785 return false; 786 } 787 InjectTouchPadEventSequence(const vector<TouchPadEvent> & events) const788 void SysUiController::InjectTouchPadEventSequence(const vector<TouchPadEvent>& events) const 789 { 790 vector<pair<bool, Point>> fingerStatus(1, make_pair(false, Point(0, 0))); 791 for (auto &event : events) { 792 auto pointerEvent = PointerEvent::Create(); 793 if (pointerEvent == nullptr) { 794 LOG_E("Creat PointerEvent failed."); 795 return; 796 } 797 pointerEvent->SetPointerId(0); 798 switch (event.stage) { 799 case ActionStage::DOWN: 800 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_SWIPE_BEGIN); 801 break; 802 case ActionStage::MOVE: 803 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_SWIPE_UPDATE); 804 break; 805 case ActionStage::UP: 806 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_SWIPE_END); 807 break; 808 default: 809 break; 810 } 811 fingerStatus[0] = make_pair(false, event.point); 812 PointerMatrix pointer; 813 AddPointerItems(*pointerEvent, fingerStatus, 0, pointer); 814 pointerEvent->SetSourceType(PointerEvent::SOURCE_TYPE_TOUCHPAD); 815 pointerEvent->SetFingerCount(event.fingerCount); 816 auto displayId = GetValidDisplayId(event.point.displayId_); 817 pointerEvent->SetTargetDisplayId(displayId); 818 InputManager::GetInstance()->SimulateInputEvent(pointerEvent, false); 819 LOG_D("Inject touchEvent to display %{public}d", displayId); 820 if (event.holdMs > 0) { 821 this_thread::sleep_for(chrono::milliseconds(event.holdMs)); 822 } 823 } 824 } 825 PutTextToClipboard(string_view text) const826 void SysUiController::PutTextToClipboard(string_view text) const 827 { 828 OHOS::testserver::TestServerClient::GetInstance().SetPasteData(string(text)); 829 } 830 IsWorkable() const831 bool SysUiController::IsWorkable() const 832 { 833 return connected_; 834 } 835 GetCharKeyCode(char ch,int32_t & code,int32_t & ctrlCode) const836 bool SysUiController::GetCharKeyCode(char ch, int32_t &code, int32_t &ctrlCode) const 837 { 838 ctrlCode = KEYCODE_NONE; 839 if (ch >= 'a' && ch <= 'z') { 840 code = OHOS::MMI::KeyEvent::KEYCODE_A + static_cast<int32_t>(ch - 'a'); 841 } else if (ch >= 'A' && ch <= 'Z') { 842 ctrlCode = OHOS::MMI::KeyEvent::KEYCODE_SHIFT_LEFT; 843 code = OHOS::MMI::KeyEvent::KEYCODE_A + static_cast<int32_t>(ch - 'A'); 844 } else if (ch >= '0' && ch <= '9') { 845 code = OHOS::MMI::KeyEvent::KEYCODE_0 + static_cast<int32_t>(ch - '0'); 846 } else if (SingleKeySymbalMap.find(ch) != SingleKeySymbalMap.end()) { 847 code = SingleKeySymbalMap.find(ch)->second; 848 } else if (MultiKeySymbalMap.find(ch) != MultiKeySymbalMap.end()) { 849 ctrlCode = OHOS::MMI::KeyEvent::KEYCODE_SHIFT_LEFT; 850 code = MultiKeySymbalMap.find(ch)->second; 851 } else { 852 return false; 853 } 854 return true; 855 } 856 TakeScreenCap(int32_t fd,std::stringstream & errReceiver,int32_t displayId,Rect rect) const857 bool SysUiController::TakeScreenCap(int32_t fd, std::stringstream &errReceiver, int32_t displayId, Rect rect) const 858 { 859 DisplayManager &displayMgr = DisplayManager::GetInstance(); 860 displayId = GetValidDisplayId(displayId); 861 // get PixelMap from DisplayManager API 862 shared_ptr<PixelMap> pixelMap; 863 if (rect.GetWidth() == 0) { 864 pixelMap = displayMgr.GetScreenshot(displayId); 865 } else { 866 Media::Rect region = {.left = rect.left_, .top = rect.top_, 867 .width = rect.right_ - rect.left_, .height = rect.bottom_ - rect.top_}; 868 Media::Size size = {.width = rect.right_ - rect.left_, .height = rect.bottom_ - rect.top_}; 869 pixelMap = displayMgr.GetScreenshot(displayId, region, size, 0); 870 } 871 if (pixelMap == nullptr) { 872 errReceiver << "Failed to get display pixelMap"; 873 return false; 874 } 875 FILE *fp = fdopen(fd, "wb"); 876 if (fp == nullptr) { 877 errReceiver << "File opening failed"; 878 return false; 879 } 880 png_structp pngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 881 if (pngStruct == nullptr) { 882 fclose(fp); 883 return false; 884 } 885 png_infop pngInfo = png_create_info_struct(pngStruct); 886 if (pngInfo == nullptr) { 887 fclose(fp); 888 png_destroy_write_struct(&pngStruct, nullptr); 889 return false; 890 } 891 png_init_io(pngStruct, fp); 892 auto width = static_cast<uint32_t>(pixelMap->GetWidth()); 893 auto height = static_cast<uint32_t>(pixelMap->GetHeight()); 894 auto data = pixelMap->GetPixels(); 895 auto stride = static_cast<uint32_t>(pixelMap->GetRowBytes()); 896 // set png header 897 static constexpr int bitmapDepth = 8; 898 png_set_IHDR(pngStruct, pngInfo, width, height, bitmapDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, 899 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 900 png_set_packing(pngStruct); // set packing info 901 png_write_info(pngStruct, pngInfo); // write to header 902 for (uint32_t column = 0; column < height; column++) { 903 png_write_row(pngStruct, data + (column * stride)); 904 } 905 // free/close 906 png_write_end(pngStruct, pngInfo); 907 png_destroy_write_struct(&pngStruct, &pngInfo); 908 (void)fclose(fp); 909 return true; 910 } 911 ConnectToSysAbility(ApiCallErr & error)912 bool SysUiController::ConnectToSysAbility(ApiCallErr &error) 913 { 914 if (connected_) { 915 return true; 916 } 917 mutex mtx; 918 unique_lock<mutex> uLock(mtx); 919 std::shared_ptr<condition_variable> condition = make_shared<condition_variable>(); 920 auto onConnectCallback = [condition]() { 921 LOG_I("Success connect to AccessibilityUITestAbility"); 922 condition->notify_all(); 923 }; 924 auto onDisConnectCallback = [this]() { this->connected_ = false; }; 925 if (g_monitorInstance_ == nullptr) { 926 g_monitorInstance_ = make_shared<UiEventMonitor>(); 927 } 928 g_monitorInstance_->SetOnAbilityConnectCallback(onConnectCallback); 929 g_monitorInstance_->SetOnAbilityDisConnectCallback(onDisConnectCallback); 930 auto ability = AccessibilityUITestAbility::GetInstance(); 931 if (ability->RegisterAbilityListener(g_monitorInstance_) != RET_OK) { 932 error = ApiCallErr(ERR_INITIALIZE_FAILED, "Can not connect to AAMS, REGISTER_LISTENER_FAILED"); 933 return false; 934 } 935 auto ret = ability->Connect(); 936 LOG_I("Connect to AAMS, result: %{public}d", ret); 937 if (ret != RET_OK) { 938 error = ApiCallErr(ERR_INITIALIZE_FAILED, "Can not connect to AAMS"); 939 if (ret == RET_ERR_CONNECTION_EXIST) { 940 error.message_ += ", RET_ERR_CONNECTION_EXIST"; 941 } else { 942 error.message_ += ", RET_ERR_AAMS"; 943 } 944 return false; 945 } 946 const auto timeout = chrono::milliseconds(7000); 947 if (condition->wait_for(uLock, timeout) == cv_status::timeout) { 948 LOG_E("Wait connection to AccessibilityUITestAbility timed out"); 949 error = ApiCallErr(ERR_INITIALIZE_FAILED, "Can not connect to AAMS, RET_TIMEOUT"); 950 return false; 951 } 952 connected_ = true; 953 return true; 954 } 955 RegisterUiEventListener(std::shared_ptr<UiEventListener> listener) const956 void SysUiController::RegisterUiEventListener(std::shared_ptr<UiEventListener> listener) const 957 { 958 g_monitorInstance_->RegisterUiEventListener(listener); 959 } 960 WaitForUiSteady(uint32_t idleThresholdMs,uint32_t timeoutMs) const961 bool SysUiController::WaitForUiSteady(uint32_t idleThresholdMs, uint32_t timeoutMs) const 962 { 963 return g_monitorInstance_->WaitEventIdle(idleThresholdMs, timeoutMs); 964 } 965 DisConnectFromSysAbility()966 void SysUiController::DisConnectFromSysAbility() 967 { 968 if (!connected_ || g_monitorInstance_ == nullptr) { 969 return; 970 } 971 connected_ = false; 972 mutex mtx; 973 unique_lock<mutex> uLock(mtx); 974 condition_variable condition; 975 auto onDisConnectCallback = [&condition]() { 976 LOG_I("Success disconnect from AccessibilityUITestAbility"); 977 condition.notify_all(); 978 }; 979 g_monitorInstance_->SetOnAbilityDisConnectCallback(onDisConnectCallback); 980 auto ability = AccessibilityUITestAbility::GetInstance(); 981 LOG_I("Start disconnect from AccessibilityUITestAbility"); 982 if (ability->Disconnect() != RET_OK) { 983 LOG_E("Failed to disconnect from AccessibilityUITestAbility"); 984 return; 985 } 986 const auto timeout = chrono::milliseconds(200); 987 if (condition.wait_for(uLock, timeout) == cv_status::timeout) { 988 LOG_E("Wait disconnection from AccessibilityUITestAbility timed out"); 989 return; 990 } 991 } 992 SetDisplayRotation(DisplayRotation rotation) const993 void SysUiController::SetDisplayRotation(DisplayRotation rotation) const 994 { 995 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 996 if (display == nullptr) { 997 LOG_E("DisplayManager init fail"); 998 return; 999 } 1000 auto screenId = display->GetScreenId(); 1001 ScreenManager &screenMgr = ScreenManager::GetInstance(); 1002 bool isLocked = false; 1003 screenMgr.IsScreenRotationLocked(isLocked); 1004 if (isLocked) { 1005 screenMgr.SetScreenRotationLocked(false); 1006 } 1007 auto screen = screenMgr.GetScreenById(screenId); 1008 if (screen == nullptr) { 1009 LOG_E("ScreenManager init fail"); 1010 return; 1011 } 1012 switch (rotation) { 1013 case ROTATION_0 : 1014 screen->SetOrientation(Orientation::VERTICAL); 1015 break; 1016 case ROTATION_90 : 1017 screen->SetOrientation(Orientation::HORIZONTAL); 1018 break; 1019 case ROTATION_180 : 1020 screen->SetOrientation(Orientation::REVERSE_VERTICAL); 1021 break; 1022 case ROTATION_270 : 1023 screen->SetOrientation(Orientation::REVERSE_HORIZONTAL); 1024 break; 1025 default : 1026 break; 1027 } 1028 } 1029 GetDisplayRotation(int32_t displayId) const1030 DisplayRotation SysUiController::GetDisplayRotation(int32_t displayId) const 1031 { 1032 DisplayManager &displayMgr = DisplayManager::GetInstance(); 1033 displayId = GetValidDisplayId(displayId); 1034 auto display = displayMgr.GetDisplayById(displayId); 1035 if (display == nullptr) { 1036 LOG_E("DisplayManager init fail"); 1037 return DisplayRotation::ROTATION_0; 1038 } 1039 auto rotation = (DisplayRotation)display->GetRotation(); 1040 return rotation; 1041 } 1042 SetDisplayRotationEnabled(bool enabled) const1043 void SysUiController::SetDisplayRotationEnabled(bool enabled) const 1044 { 1045 ScreenManager &screenMgr = ScreenManager::GetInstance(); 1046 screenMgr.SetScreenRotationLocked(!enabled); 1047 } 1048 GetDisplaySize(int32_t displayId) const1049 Point SysUiController::GetDisplaySize(int32_t displayId) const 1050 { 1051 DisplayManager &displayMgr = DisplayManager::GetInstance(); 1052 displayId = GetValidDisplayId(displayId); 1053 auto display = displayMgr.GetDisplayById(displayId); 1054 if (display == nullptr) { 1055 LOG_E("DisplayManager init fail"); 1056 return {0, 0}; 1057 } 1058 auto width = display->GetWidth(); 1059 auto height = display->GetHeight(); 1060 LOG_D("GetDisplaysize in display %{public}d, width: %{public}d, height: %{public}d", displayId, width, height); 1061 auto virtualDisplay = displayMgr.GetDisplayById(VIRTUAL_DISPLAY_ID); 1062 if (displayId == 0 && virtualDisplay != nullptr) { 1063 auto virtualwidth = virtualDisplay->GetWidth(); 1064 auto virtualheight = virtualDisplay->GetHeight(); 1065 auto foldArea = GetFoldArea(); 1066 auto foldAreaWidth = foldArea.right_ - foldArea.left_; 1067 auto foldAreaHeight = foldArea.bottom_ - foldArea.top_; 1068 LOG_D("GetDisplaysize in virtual display, width: %{public}d, height: %{public}d", 1069 virtualwidth, virtualheight); 1070 LOG_D("GetDisplaysize in foldArea, width: %{public}d, height: %{public}d", foldAreaWidth, foldAreaHeight); 1071 height = height + virtualheight + foldAreaHeight; 1072 } 1073 Point result(width, height, displayId); 1074 return result; 1075 } 1076 GetDisplayDensity(int32_t displayId) const1077 Point SysUiController::GetDisplayDensity(int32_t displayId) const 1078 { 1079 DisplayManager &displayMgr = DisplayManager::GetInstance(); 1080 displayId = GetValidDisplayId(displayId); 1081 auto display = displayMgr.GetDisplayById(displayId); 1082 if (display == nullptr) { 1083 LOG_E("DisplayManager init fail"); 1084 return {0, 0}; 1085 } 1086 auto rate = display->GetVirtualPixelRatio(); 1087 Point displaySize = GetDisplaySize(displayId); 1088 Point result(displaySize.px_ * rate, displaySize.py_ * rate); 1089 return result; 1090 } 1091 IsScreenOn() const1092 bool SysUiController::IsScreenOn() const 1093 { 1094 DisplayManager &displayMgr = DisplayManager::GetInstance(); 1095 auto displayId = displayMgr.GetDefaultDisplayId(); 1096 auto state = displayMgr.GetDisplayState(displayId); 1097 return (state != DisplayState::OFF); 1098 } 1099 1100 class OnSaLoadCallback : public SystemAbilityLoadCallbackStub { 1101 public: OnSaLoadCallback(mutex & mutex)1102 explicit OnSaLoadCallback(mutex &mutex): mutex_(mutex) {}; ~OnSaLoadCallback()1103 ~OnSaLoadCallback() {}; OnLoadSystemAbilitySuccess(int32_t systemAbilityId,const sptr<IRemoteObject> & remoteObject)1104 void OnLoadSystemAbilitySuccess(int32_t systemAbilityId, const sptr<IRemoteObject>& remoteObject) override 1105 { 1106 if (systemAbilityId == OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID) { 1107 remoteObject_ = remoteObject; 1108 mutex_.unlock(); 1109 } 1110 } OnLoadSystemAbilityFail(int32_t systemAbilityId)1111 void OnLoadSystemAbilityFail(int32_t systemAbilityId) override 1112 { 1113 if (systemAbilityId == OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID) { 1114 mutex_.unlock(); 1115 } 1116 } 1117 GetSaObject()1118 sptr<IRemoteObject> GetSaObject() 1119 { 1120 return remoteObject_; 1121 } 1122 1123 private: 1124 mutex &mutex_; 1125 sptr<IRemoteObject> remoteObject_ = nullptr; 1126 }; 1127 CreateHidumperCmd(const std::string & windowId,vector<u16string> & result)1128 static void CreateHidumperCmd(const std::string &windowId, vector<u16string> &result) 1129 { 1130 result.emplace_back(u"hidumper"); 1131 result.emplace_back(u"-s"); 1132 result.emplace_back(u"WindowManagerService"); 1133 result.emplace_back(u"-a"); 1134 auto winIdInUtf16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(windowId); 1135 auto arg = u16string(u"-w ").append(winIdInUtf16).append(u" -default -lastpage"); 1136 result.emplace_back(move(arg)); 1137 } 1138 GetHidumperInfo(std::string windowId,char ** buf,size_t & len)1139 void SysUiController::GetHidumperInfo(std::string windowId, char **buf, size_t &len) 1140 { 1141 #ifdef HIDUMPER_ENABLED 1142 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); 1143 // wati SA start 1144 constexpr auto delayMs = 2000; 1145 this_thread::sleep_for(chrono::milliseconds(delayMs)); 1146 if (sam == nullptr) { 1147 LOG_E("Get samgr failed"); 1148 return; 1149 } 1150 auto remoteObject = sam->CheckSystemAbility(OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID); 1151 if (remoteObject == nullptr) { 1152 mutex lock; 1153 lock.lock(); 1154 sptr<OnSaLoadCallback> loadCallback = new OnSaLoadCallback(lock); 1155 if (sam->LoadSystemAbility(OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID, loadCallback) != ERR_OK) { 1156 LOG_E("Schedule LoadSystemAbility failed"); 1157 lock.unlock(); 1158 return; 1159 } 1160 LOG_E("Schedule LoadSystemAbility succeed"); 1161 lock.unlock(); 1162 remoteObject = loadCallback->GetSaObject(); 1163 LOG_E("LoadSystemAbility callbacked, result = %{public}s", remoteObject == nullptr ? "FAIL" : "SUCCESS"); 1164 } 1165 if (remoteObject == nullptr) { 1166 LOG_E("remoteObject is null"); 1167 return; 1168 } 1169 // run dump command 1170 sptr<IDumpBroker> client = iface_cast<IDumpBroker>(remoteObject); 1171 if (client == nullptr) { 1172 LOG_E("IDumpBroker converts failed"); 1173 return; 1174 } 1175 auto fd = memfd_create("dummy_file", 2); 1176 ftruncate(fd, 0); 1177 vector<u16string> args; 1178 CreateHidumperCmd(windowId, args); 1179 client->Request(args, fd); 1180 auto size = lseek(fd, 0, SEEK_END); 1181 char *tempBuf = new char[size + 1]; 1182 lseek(fd, 0, SEEK_SET); 1183 read(fd, tempBuf, size); 1184 *buf = tempBuf; 1185 len = size; 1186 close(fd); 1187 #else 1188 *buf = nullptr; 1189 len = 0; 1190 #endif 1191 } 1192 } // namespace OHOS::uitest