• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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