• 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 <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 "system_ability_definition.h"
30 #endif
31 #include "pasteboard_client.h"
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 
43 using namespace std;
44 using namespace chrono;
45 
46 namespace OHOS::uitest {
47     using namespace std;
48     using namespace nlohmann;
49     using namespace OHOS::MMI;
50     using namespace OHOS::Accessibility;
51     using namespace OHOS::Rosen;
52     using namespace OHOS::Media;
53     using namespace OHOS::HiviewDFX;
54     using namespace OHOS;
55 
56     class UiEventMonitor final : public AccessibleAbilityListener {
57     public:
58         virtual ~UiEventMonitor() override = default;
59 
60         void OnAbilityConnected() override;
61 
62         void OnAbilityDisconnected() override;
63 
64         void OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo) override;
65 
66         void SetOnAbilityConnectCallback(function<void()> onConnectCb);
67 
68         void SetOnAbilityDisConnectCallback(function<void()> onDisConnectCb);
69 
OnKeyPressEvent(const shared_ptr<MMI::KeyEvent> & keyEvent)70         bool OnKeyPressEvent(const shared_ptr<MMI::KeyEvent> &keyEvent) override
71         {
72             return false;
73         }
74 
75         uint64_t GetLastEventMillis();
76 
77         bool WaitEventIdle(uint32_t idleThresholdMs, uint32_t timeoutMs);
78 
79         void WaitScrollCompelete();
80 
81         void RegisterUiEventListener(shared_ptr<UiEventListener> listerner);
82 
83     private:
84         function<void()> onConnectCallback_ = nullptr;
85         function<void()> onDisConnectCallback_ = nullptr;
86         atomic<uint64_t> lastEventMillis_ = 0;
87         atomic<uint64_t> lastScrollBeginEventMillis_ = 0;
88         atomic<bool> scrollCompelete_ = true;
89         vector<shared_ptr<UiEventListener>> listeners_;
90     };
91 
92     struct EventSpec {
93         std::string_view componentTyep;
94         int32_t eventType;
95         std::string_view event;
96     };
97 
98     static constexpr EventSpec WATCHED_EVENTS[] = {
99         {"Toast", WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_SUBTREE, "toastShow"},
100         {"AlertDialog", WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_SUBTREE, "dialogShow"}
101     };
102 
GetWatchedEvent(const AccessibilityEventInfo & eventInfo)103     static std::string GetWatchedEvent(const AccessibilityEventInfo &eventInfo)
104     {
105         for (unsigned long index = 0; index < sizeof(WATCHED_EVENTS) / sizeof(EventSpec); index++) {
106             if (WATCHED_EVENTS[index].componentTyep == eventInfo.GetComponentType() &&
107                 WATCHED_EVENTS[index].eventType == eventInfo.GetWindowContentChangeTypes()) {
108                 LOG_W("Capture event: %{public}s", WATCHED_EVENTS[index].event.data());
109                 return string(WATCHED_EVENTS[index].event);
110             }
111         }
112         return "undefine";
113     }
114 
115     // UiEventMonitor instance.
116     static shared_ptr<UiEventMonitor> g_monitorInstance_ = make_shared<UiEventMonitor>();
117 
SetOnAbilityConnectCallback(function<void ()> onConnectCb)118     void UiEventMonitor::SetOnAbilityConnectCallback(function<void()> onConnectCb)
119     {
120         onConnectCallback_ = std::move(onConnectCb);
121     }
122 
SetOnAbilityDisConnectCallback(function<void ()> onDisConnectCb)123     void UiEventMonitor::SetOnAbilityDisConnectCallback(function<void()> onDisConnectCb)
124     {
125         onDisConnectCallback_ = std::move(onDisConnectCb);
126     }
127 
OnAbilityConnected()128     void UiEventMonitor::OnAbilityConnected()
129     {
130         if (onConnectCallback_ != nullptr) {
131             onConnectCallback_();
132         }
133     }
134 
OnAbilityDisconnected()135     void UiEventMonitor::OnAbilityDisconnected()
136     {
137         if (onDisConnectCallback_ != nullptr) {
138             onDisConnectCallback_();
139         }
140     }
141 
142     // the monitored events
143     static constexpr uint32_t EVENT_MASK = EventType::TYPE_VIEW_TEXT_UPDATE_EVENT |
144                                            EventType::TYPE_PAGE_STATE_UPDATE |
145                                            EventType::TYPE_PAGE_CONTENT_UPDATE |
146                                            EventType::TYPE_VIEW_SCROLLED_EVENT |
147                                            EventType::TYPE_WINDOW_UPDATE;
148 
RegisterUiEventListener(std::shared_ptr<UiEventListener> listerner)149     void UiEventMonitor::RegisterUiEventListener(std::shared_ptr<UiEventListener> listerner)
150     {
151         listeners_.emplace_back(listerner);
152     }
153 
OnAccessibilityEvent(const AccessibilityEventInfo & eventInfo)154     void UiEventMonitor::OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo)
155     {
156         auto eventType = eventInfo.GetEventType();
157         LOG_W("OnEvent:0x%{public}x", eventType);
158         auto capturedEvent = GetWatchedEvent(eventInfo);
159         if (eventType == Accessibility::EventType::TYPE_VIEW_SCROLLED_START) {
160             LOG_I("Capture scroll begin");
161             scrollCompelete_.store(false);
162             lastScrollBeginEventMillis_.store(GetCurrentMillisecond());
163         }
164         if (eventType == Accessibility::EventType::TYPE_VIEW_SCROLLED_EVENT) {
165             LOG_I("Capture scroll end");
166             scrollCompelete_.store(true);
167         }
168         if (capturedEvent != "undefine") {
169             auto bundleName = eventInfo.GetBundleName();
170             auto contentList = eventInfo.GetContentList();
171             auto text = !contentList.empty() ? contentList[0] : "";
172             auto type = eventInfo.GetComponentType();
173             UiEventSourceInfo uiEventSourceInfo = {bundleName, text, type};
174             for (auto &listener : listeners_) {
175                 listener->OnEvent(capturedEvent, uiEventSourceInfo);
176             }
177         }
178         if ((eventInfo.GetEventType() & EVENT_MASK) > 0) {
179             lastEventMillis_.store(GetCurrentMillisecond());
180         }
181     }
182 
GetLastEventMillis()183     uint64_t UiEventMonitor::GetLastEventMillis()
184     {
185         if (lastEventMillis_.load() <= 0) {
186             lastEventMillis_.store(GetCurrentMillisecond());
187         }
188         return lastEventMillis_.load();
189     }
190 
WaitScrollCompelete()191     void UiEventMonitor::WaitScrollCompelete()
192     {
193         if (scrollCompelete_.load()) {
194             return;
195         }
196         const auto currentMs = GetCurrentMillisecond();
197         if (lastScrollBeginEventMillis_.load() <= 0) {
198             lastScrollBeginEventMillis_.store(currentMs);
199         }
200         const auto idleThresholdMs = 10000;
201         if (currentMs - lastScrollBeginEventMillis_.load() >= idleThresholdMs) {
202             LOG_E("wai for scrollEnd event timeout.");
203             scrollCompelete_.store(true);
204             return;
205         }
206         static constexpr auto sliceMs = 10;
207         this_thread::sleep_for(chrono::milliseconds(sliceMs));
208         return WaitScrollCompelete();
209     }
210 
WaitEventIdle(uint32_t idleThresholdMs,uint32_t timeoutMs)211     bool UiEventMonitor::WaitEventIdle(uint32_t idleThresholdMs, uint32_t timeoutMs)
212     {
213         const auto currentMs = GetCurrentMillisecond();
214         if (lastEventMillis_.load() <= 0) {
215             lastEventMillis_.store(currentMs);
216         }
217         if (currentMs - lastEventMillis_.load() >= idleThresholdMs) {
218             return true;
219         }
220         static constexpr auto sliceMs = 10;
221         this_thread::sleep_for(chrono::milliseconds(sliceMs));
222         if (timeoutMs <= sliceMs) {
223             return false;
224         }
225         return WaitEventIdle(idleThresholdMs, timeoutMs - sliceMs);
226     }
227 
SysUiController()228     SysUiController::SysUiController() : UiController() {}
229 
~SysUiController()230     SysUiController::~SysUiController()
231     {
232         DisConnectFromSysAbility();
233     }
234 
Initialize()235     bool SysUiController::Initialize()
236     {
237         return this->ConnectToSysAbility();
238     }
239 
GetVisibleRect(Rect windowBounds,Accessibility::Rect nodeBounds)240     static Rect GetVisibleRect(Rect windowBounds, Accessibility::Rect nodeBounds)
241     {
242         auto leftX = nodeBounds.GetLeftTopXScreenPostion();
243         auto topY = nodeBounds.GetLeftTopYScreenPostion();
244         auto rightX = nodeBounds.GetRightBottomXScreenPostion();
245         auto bottomY = nodeBounds.GetRightBottomYScreenPostion();
246         Rect newBounds((leftX < windowBounds.left_) ? windowBounds.left_ : leftX,
247                        (rightX > windowBounds.right_) ? windowBounds.right_ : rightX,
248                        (topY < windowBounds.top_) ? windowBounds.top_ : topY,
249                        (bottomY > windowBounds.bottom_) ? windowBounds.bottom_ : bottomY);
250         return newBounds;
251     }
252 
InflateWindowInfo(AccessibilityWindowInfo & node,Window & info)253     static void InflateWindowInfo(AccessibilityWindowInfo& node, Window& info)
254     {
255         info.focused_ = node.IsFocused();
256         info.actived_ = node.IsActive();
257         info.decoratorEnabled_ = node.IsDecorEnable();
258         // get bundle name by root node
259         AccessibilityElementInfo element;
260         LOG_D("Start Get Bundle Name by WindowId %{public}d", node.GetWindowId());
261         if (AccessibilityUITestAbility::GetInstance()->GetRootByWindow(node, element) != RET_OK) {
262             LOG_E("Failed Get Bundle Name by WindowId %{public}d", node.GetWindowId());
263         } else {
264             std::string app = element.GetBundleName();
265             LOG_I("End Get Bundle Name by WindowId %{public}d, app is %{public}s", node.GetWindowId(), app.data());
266             info.bundleName_ = app;
267             const auto foreAbility = AAFwk::AbilityManagerClient::GetInstance()->GetTopAbility();
268             info.abilityName_ = (app == foreAbility.GetBundleName()) ? foreAbility.GetAbilityName() : "";
269             info.pagePath_ = (app == foreAbility.GetBundleName()) ? element.GetPagePath() : "";
270         }
271         info.mode_ = WindowMode::UNKNOWN;
272         const auto origMode = static_cast<OHOS::Rosen::WindowMode>(node.GetWindowMode());
273         switch (origMode) {
274             case OHOS::Rosen::WindowMode::WINDOW_MODE_FULLSCREEN:
275                 info.mode_ = WindowMode::FULLSCREEN;
276                 break;
277             case OHOS::Rosen::WindowMode::WINDOW_MODE_SPLIT_PRIMARY:
278                 info.mode_ = WindowMode::SPLIT_PRIMARY;
279                 break;
280             case OHOS::Rosen::WindowMode::WINDOW_MODE_SPLIT_SECONDARY:
281                 info.mode_ = WindowMode::SPLIT_SECONDARY;
282                 break;
283             case OHOS::Rosen::WindowMode::WINDOW_MODE_FLOATING:
284                 info.mode_ = WindowMode::FLOATING;
285                 break;
286             case OHOS::Rosen::WindowMode::WINDOW_MODE_PIP:
287                 info.mode_ = WindowMode::PIP;
288                 break;
289             default:
290                 info.mode_ = WindowMode::UNKNOWN;
291                 break;
292         }
293     }
294 
GetAamsWindowInfos(vector<AccessibilityWindowInfo> & windows)295     static bool GetAamsWindowInfos(vector<AccessibilityWindowInfo> &windows)
296     {
297         auto ability = AccessibilityUITestAbility::GetInstance();
298         g_monitorInstance_->WaitScrollCompelete();
299         if (ability->GetWindows(windows) != RET_OK) {
300             LOG_W("GetWindows from AccessibilityUITestAbility failed");
301             return false;
302         }
303         sort(windows.begin(), windows.end(), [](auto &w1, auto &w2) -> bool {
304             return w1.GetWindowLayer() > w2.GetWindowLayer();
305         });
306         return true;
307     }
308 
GetUiWindows(std::vector<Window> & out)309     void SysUiController::GetUiWindows(std::vector<Window> &out)
310     {
311         std::lock_guard<std::mutex> dumpLocker(dumpMtx); // disallow concurrent dumpUi
312         if (!connected_ && !ConnectToSysAbility()) {
313             LOG_W("Connect to AccessibilityUITestAbility failed");
314             return;
315         }
316         vector<AccessibilityWindowInfo> windows;
317         LOG_I("Get Window root info");
318         if (!GetAamsWindowInfos(windows)) {
319             return;
320         }
321         LOG_D("End Get Window root info");
322         auto screenSize = GetDisplaySize();
323         auto screenRect = Rect(0, screenSize.px_, 0, screenSize.py_);
324         std::vector<Rect> overplays;
325         // window wrapper
326         for (auto &win : windows) {
327             Rect winRectInScreen = GetVisibleRect(screenRect, win.GetRectInScreen());
328             Rect visibleArea = winRectInScreen;
329             if (!RectAlgorithm::ComputeMaxVisibleRegion(winRectInScreen, overplays, visibleArea)) {
330                 LOG_I("window is covered, windowId : %{public}d, layer is %{public}d", win.GetWindowId(),
331                       win.GetWindowLayer());
332                 continue;
333             }
334             LOG_I("window is visible, windowId: %{public}d, active: %{public}d, focus: %{public}d, layer: %{public}d",
335                 win.GetWindowId(), win.IsActive(), win.IsFocused(), win.GetWindowLayer());
336             Window winWrapper{win.GetWindowId()};
337             InflateWindowInfo(win, winWrapper);
338             winWrapper.bounds_ = winRectInScreen;
339             for (const auto &overWin : overplays) {
340                 Rect intersectionRect{0, 0, 0, 0};
341                 if (RectAlgorithm::ComputeIntersection(winRectInScreen, overWin, intersectionRect)) {
342                     winWrapper.invisibleBoundsVec_.emplace_back(overWin);
343                 }
344             }
345             overplays.emplace_back(winRectInScreen);
346             out.emplace_back(std::move(winWrapper));
347         }
348     }
349 
GetWidgetsInWindow(const Window & winInfo,unique_ptr<ElementNodeIterator> & elementIterator)350     bool SysUiController::GetWidgetsInWindow(const Window &winInfo, unique_ptr<ElementNodeIterator> &elementIterator)
351     {
352         std::lock_guard<std::mutex> dumpLocker(dumpMtx); // disallow concurrent dumpUi
353         if (!connected_) {
354             LOG_W("Connect to AccessibilityUITestAbility failed");
355             return false;
356         }
357         std::vector<AccessibilityElementInfo> elementInfos;
358         AccessibilityWindowInfo window;
359         LOG_D("Get Window by WindowId %{public}d", winInfo.id_);
360         if (AccessibilityUITestAbility::GetInstance()->GetWindow(winInfo.id_, window) != RET_OK) {
361             LOG_E("GetWindowInfo failed, windowId: %{public}d", winInfo.id_);
362             return false;
363         }
364         LOG_I("Start Get nodes from window by WindowId %{public}d", winInfo.id_);
365         if (AccessibilityUITestAbility::GetInstance()->GetRootByWindowBatch(window, elementInfos) != RET_OK) {
366             LOG_E("GetRootByWindowBatch failed, windowId: %{public}d", winInfo.id_);
367             return false;
368         } else {
369             LOG_I("End Get nodes from window by WindowId %{public}d, node size is %{public}zu, appId: %{public}s",
370                   winInfo.id_, elementInfos.size(), winInfo.bundleName_.data());
371             elementIterator = std::make_unique<ElementNodeIteratorImpl>(elementInfos);
372         }
373         return true;
374     }
375 
InjectTouchEventSequence(const PointerMatrix & events) const376     void SysUiController::InjectTouchEventSequence(const PointerMatrix &events) const
377     {
378         for (uint32_t step = 0; step < events.GetSteps(); step++) {
379             auto pointerEvent = PointerEvent::Create();
380             for (uint32_t finger = 0; finger < events.GetFingers(); finger++) {
381                 pointerEvent->SetPointerId(finger);
382                 PointerEvent::PointerItem pinterItem;
383                 pinterItem.SetPointerId(finger);
384                 pinterItem.SetDisplayX(events.At(finger, step).point_.px_);
385                 pinterItem.SetDisplayY(events.At(finger, step).point_.py_);
386                 switch (events.At(finger, step).stage_) {
387                     case ActionStage::DOWN:
388                         pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_DOWN);
389                         break;
390                     case ActionStage::MOVE:
391                         pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_MOVE);
392                         break;
393                     case ActionStage::UP:
394                         pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_UP);
395                         break;
396                     default:
397                         break;
398                 }
399                 pinterItem.SetPressed(events.At(finger, step).stage_ != ActionStage::UP);
400                 pointerEvent->AddPointerItem(pinterItem);
401                 pointerEvent->SetSourceType(PointerEvent::SOURCE_TYPE_TOUCHSCREEN);
402                 DisplayManager &displayMgr = DisplayManager::GetInstance();
403                 pointerEvent->SetTargetDisplayId(displayMgr.GetDefaultDisplayId());
404                 InputManager::GetInstance()->SimulateInputEvent(pointerEvent);
405                 if (events.At(finger, step).holdMs_ > 0) {
406                     this_thread::sleep_for(chrono::milliseconds(events.At(finger, step).holdMs_));
407                 }
408             }
409         }
410     }
411 
SetMousePointerItemAttr(const MouseEvent & event,PointerEvent::PointerItem & item)412     static void SetMousePointerItemAttr(const MouseEvent &event, PointerEvent::PointerItem &item)
413     {
414         item.SetPointerId(0);
415         item.SetToolType(PointerEvent::TOOL_TYPE_MOUSE);
416         item.SetDisplayX(event.point_.px_);
417         item.SetDisplayY(event.point_.py_);
418         item.SetPressed(false);
419         item.SetDownTime(0);
420     }
421 
InjectMouseEvent(const MouseEvent & event) const422     void SysUiController::InjectMouseEvent(const MouseEvent &event) const
423     {
424         auto pointerEvent = PointerEvent::Create();
425         PointerEvent::PointerItem item;
426         pointerEvent->SetSourceType(PointerEvent::SOURCE_TYPE_MOUSE);
427         pointerEvent->SetPointerId(0);
428         pointerEvent->SetButtonId(event.button_);
429         SetMousePointerItemAttr(event, item);
430         constexpr double axialValue = 15;
431         static bool flag = true;
432         auto injectAxialValue = axialValue;
433         switch (event.stage_) {
434             case ActionStage::DOWN:
435                 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN);
436                 pointerEvent->SetButtonId(event.button_);
437                 pointerEvent->SetButtonPressed(event.button_);
438                 item.SetPressed(true);
439                 break;
440             case ActionStage::MOVE:
441                 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_MOVE);
442                 break;
443             case ActionStage::UP:
444                 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_BUTTON_UP);
445                 pointerEvent->SetButtonId(event.button_);
446                 pointerEvent->SetButtonPressed(event.button_);
447                 break;
448             case ActionStage::AXIS_UP:
449                 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_BEGIN);
450                 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, -axialValue);
451                 flag = false;
452                 break;
453             case ActionStage::AXIS_DOWN:
454                 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_BEGIN);
455                 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, axialValue);
456                 flag = true;
457                 break;
458             case ActionStage::AXIS_STOP:
459                 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_END);
460                 injectAxialValue = flag ? axialValue : -axialValue;
461                 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, injectAxialValue);
462                 break;
463             default:
464                 break;
465         }
466         pointerEvent->AddPointerItem(item);
467         InputManager::GetInstance()->SimulateInputEvent(pointerEvent);
468         this_thread::sleep_for(chrono::milliseconds(event.holdMs_));
469     }
470 
InjectMouseEventSequence(const vector<MouseEvent> & events) const471     void SysUiController::InjectMouseEventSequence(const vector<MouseEvent> &events) const
472     {
473         for (auto &event : events) {
474             auto keyEvents = event.keyEvents_;
475             if (!keyEvents.empty() && keyEvents.front().stage_ == ActionStage::DOWN) {
476                 InjectKeyEventSequence(keyEvents);
477                 InjectMouseEvent(event);
478             } else {
479                 InjectMouseEvent(event);
480                 InjectKeyEventSequence(keyEvents);
481             }
482         }
483     }
484 
InjectKeyEventSequence(const vector<KeyEvent> & events) const485     void SysUiController::InjectKeyEventSequence(const vector<KeyEvent> &events) const
486     {
487         static vector<int32_t> downKeys;
488         for (auto &event : events) {
489             if (event.code_ == KEYCODE_NONE) {
490                 continue;
491             }
492             if (event.stage_ == ActionStage::UP) {
493                 auto iter = std::find(downKeys.begin(), downKeys.end(), event.code_);
494                 if (iter == downKeys.end()) {
495                     LOG_W("Cannot release a not-pressed key: %{public}d", event.code_);
496                     continue;
497                 }
498                 downKeys.erase(iter);
499                 auto keyEvent = OHOS::MMI::KeyEvent::Create();
500                 keyEvent->SetKeyCode(event.code_);
501                 keyEvent->SetKeyAction(OHOS::MMI::KeyEvent::KEY_ACTION_UP);
502                 OHOS::MMI::KeyEvent::KeyItem keyItem;
503                 keyItem.SetKeyCode(event.code_);
504                 keyItem.SetPressed(true);
505                 keyEvent->AddKeyItem(keyItem);
506                 InputManager::GetInstance()->SimulateInputEvent(keyEvent);
507             } else {
508                 downKeys.push_back(event.code_);
509                 auto keyEvent = OHOS::MMI::KeyEvent::Create();
510                 for (auto downKey : downKeys) {
511                     keyEvent->SetKeyCode(downKey);
512                     keyEvent->SetKeyAction(OHOS::MMI::KeyEvent::KEY_ACTION_DOWN);
513                     OHOS::MMI::KeyEvent::KeyItem keyItem;
514                     keyItem.SetKeyCode(downKey);
515                     keyItem.SetPressed(true);
516                     keyEvent->AddKeyItem(keyItem);
517                 }
518                 InputManager::GetInstance()->SimulateInputEvent(keyEvent);
519                 if (event.holdMs_ > 0) {
520                     this_thread::sleep_for(chrono::milliseconds(event.holdMs_));
521                 }
522             }
523         }
524         // check not released keys
525         for (auto downKey : downKeys) {
526             LOG_W("Key event sequence injections done with not-released key: %{public}d", downKey);
527         }
528     }
529 
PutTextToClipboard(string_view text) const530     void SysUiController::PutTextToClipboard(string_view text) const
531     {
532         auto pasteBoardMgr = MiscServices::PasteboardClient::GetInstance();
533         pasteBoardMgr->Clear();
534         auto pasteData = pasteBoardMgr->CreatePlainTextData(string(text));
535         pasteBoardMgr->SetPasteData(*pasteData);
536     }
537 
IsWorkable() const538     bool SysUiController::IsWorkable() const
539     {
540         return connected_;
541     }
542 
GetCharKeyCode(char ch,int32_t & code,int32_t & ctrlCode) const543     bool SysUiController::GetCharKeyCode(char ch, int32_t &code, int32_t &ctrlCode) const
544     {
545         ctrlCode = KEYCODE_NONE;
546         if (ch >= 'a' && ch <= 'z') {
547             code = OHOS::MMI::KeyEvent::KEYCODE_A + static_cast<int32_t>(ch - 'a');
548         } else if (ch >= 'A' && ch <= 'Z') {
549             ctrlCode = OHOS::MMI::KeyEvent::KEYCODE_SHIFT_LEFT;
550             code = OHOS::MMI::KeyEvent::KEYCODE_A + static_cast<int32_t>(ch - 'A');
551         } else if (ch >= '0' && ch <= '9') {
552             code = OHOS::MMI::KeyEvent::KEYCODE_0 + static_cast<int32_t>(ch - '0');
553         } else {
554             return false;
555         }
556         return true;
557     }
558 
TakeScreenCap(int32_t fd,std::stringstream & errReceiver,Rect rect) const559     bool SysUiController::TakeScreenCap(int32_t fd, std::stringstream &errReceiver, Rect rect) const
560     {
561         DisplayManager &displayMgr = DisplayManager::GetInstance();
562         // get PixelMap from DisplayManager API
563         shared_ptr<PixelMap> pixelMap;
564         if (rect.GetWidth() == 0) {
565             pixelMap = displayMgr.GetScreenshot(displayMgr.GetDefaultDisplayId());
566         } else {
567             Media::Rect region = {.left = rect.left_, .top = rect.top_,
568                 .width = rect.right_ - rect.left_, .height = rect.bottom_ - rect.top_};
569             Media::Size size = {.width = rect.right_ - rect.left_, .height = rect.bottom_ - rect.top_};
570             pixelMap = displayMgr.GetScreenshot(displayMgr.GetDefaultDisplayId(), region, size, 0);
571         }
572         if (pixelMap == nullptr) {
573             errReceiver << "Failed to get display pixelMap";
574             return false;
575         }
576         FILE *fp = fdopen(fd, "wb");
577         if (fp == nullptr) {
578             perror("File opening failed");
579             errReceiver << "File opening failed";
580             return false;
581         }
582         png_structp pngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
583         if (pngStruct == nullptr) {
584             fclose(fp);
585             return false;
586         }
587         png_infop pngInfo = png_create_info_struct(pngStruct);
588         if (pngInfo == nullptr) {
589             fclose(fp);
590             png_destroy_write_struct(&pngStruct, nullptr);
591             return false;
592         }
593         png_init_io(pngStruct, fp);
594         auto width = static_cast<uint32_t>(pixelMap->GetWidth());
595         auto height = static_cast<uint32_t>(pixelMap->GetHeight());
596         auto data = pixelMap->GetPixels();
597         auto stride = static_cast<uint32_t>(pixelMap->GetRowBytes());
598         // set png header
599         static constexpr int bitmapDepth = 8;
600         png_set_IHDR(pngStruct, pngInfo, width, height, bitmapDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
601                      PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
602         png_set_packing(pngStruct); // set packing info
603         png_write_info(pngStruct, pngInfo); // write to header
604         for (uint32_t column = 0; column < height; column++) {
605             png_write_row(pngStruct, data + (column * stride));
606         }
607         // free/close
608         png_write_end(pngStruct, pngInfo);
609         png_destroy_write_struct(&pngStruct, &pngInfo);
610         (void)fclose(fp);
611         return true;
612     }
613 
ConnectToSysAbility()614     bool SysUiController::ConnectToSysAbility()
615     {
616         if (connected_) {
617             return true;
618         }
619         mutex mtx;
620         unique_lock<mutex> uLock(mtx);
621         std::shared_ptr<condition_variable> condition = make_shared<condition_variable>();
622         auto onConnectCallback = [condition]() {
623             LOG_I("Success connect to AccessibilityUITestAbility");
624             condition->notify_all();
625         };
626         auto onDisConnectCallback = [this]() { this->connected_ = false; };
627         if (g_monitorInstance_ == nullptr) {
628             g_monitorInstance_ = make_shared<UiEventMonitor>();
629         }
630         g_monitorInstance_->SetOnAbilityConnectCallback(onConnectCallback);
631         g_monitorInstance_->SetOnAbilityDisConnectCallback(onDisConnectCallback);
632         auto ability = AccessibilityUITestAbility::GetInstance();
633         if (ability->RegisterAbilityListener(g_monitorInstance_) != RET_OK) {
634             LOG_E("Failed to register UiEventMonitor");
635             return false;
636         }
637         auto ret = ability->Connect();
638         switch (ret) {
639             case (RET_ERR_INVALID_PARAM):
640                 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_INVALID_PARAM");
641                 return false;
642             case (RET_ERR_NULLPTR):
643                 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_NULLPTR");
644                 return false;
645             case (RET_ERR_CONNECTION_EXIST):
646                 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_CONNECTION_EXIST");
647                 return false;
648             case (RET_ERR_IPC_FAILED):
649                 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_IPC_FAILED");
650                 return false;
651             case (RET_ERR_SAMGR):
652                 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_SAMGR");
653                 return false;
654             default:
655                 break;
656         }
657         const auto timeout = chrono::milliseconds(1000);
658         if (condition->wait_for(uLock, timeout) == cv_status::timeout) {
659             LOG_E("Wait connection to AccessibilityUITestAbility timed out");
660             return false;
661         }
662         connected_ = true;
663         return true;
664     }
665 
RegisterUiEventListener(std::shared_ptr<UiEventListener> listener) const666     void SysUiController::RegisterUiEventListener(std::shared_ptr<UiEventListener> listener) const
667     {
668         g_monitorInstance_->RegisterUiEventListener(listener);
669     }
670 
WaitForUiSteady(uint32_t idleThresholdMs,uint32_t timeoutMs) const671     bool SysUiController::WaitForUiSteady(uint32_t idleThresholdMs, uint32_t timeoutMs) const
672     {
673         return g_monitorInstance_->WaitEventIdle(idleThresholdMs, timeoutMs);
674     }
675 
DisConnectFromSysAbility()676     void SysUiController::DisConnectFromSysAbility()
677     {
678         if (!connected_ || g_monitorInstance_ == nullptr) {
679             return;
680         }
681         connected_ = false;
682         mutex mtx;
683         unique_lock<mutex> uLock(mtx);
684         condition_variable condition;
685         auto onDisConnectCallback = [&condition]() {
686             LOG_I("Success disconnect from AccessibilityUITestAbility");
687             condition.notify_all();
688         };
689         g_monitorInstance_->SetOnAbilityDisConnectCallback(onDisConnectCallback);
690         auto ability = AccessibilityUITestAbility::GetInstance();
691         LOG_I("Start disconnect from AccessibilityUITestAbility");
692         if (ability->Disconnect() != RET_OK) {
693             LOG_E("Failed to disconnect from AccessibilityUITestAbility");
694             return;
695         }
696         const auto timeout = chrono::milliseconds(200);
697         if (condition.wait_for(uLock, timeout) == cv_status::timeout) {
698             LOG_E("Wait disconnection from AccessibilityUITestAbility timed out");
699             return;
700         }
701     }
702 
SetDisplayRotation(DisplayRotation rotation) const703     void SysUiController::SetDisplayRotation(DisplayRotation rotation) const
704     {
705         auto display = DisplayManager::GetInstance().GetDefaultDisplay();
706         if (display == nullptr) {
707             LOG_E("DisplayManager init fail");
708             return;
709         }
710         auto screenId = display->GetScreenId();
711         ScreenManager &screenMgr = ScreenManager::GetInstance();
712         DCHECK(screenMgr);
713         bool isLocked = false;
714         screenMgr.IsScreenRotationLocked(isLocked);
715         if (isLocked) {
716             screenMgr.SetScreenRotationLocked(false);
717         }
718         auto screen = screenMgr.GetScreenById(screenId);
719         if (screen == nullptr) {
720             LOG_E("ScreenManager init fail");
721             return;
722         }
723         switch (rotation) {
724             case ROTATION_0 :
725                 screen->SetOrientation(Orientation::VERTICAL);
726                 break;
727             case ROTATION_90 :
728                 screen->SetOrientation(Orientation::HORIZONTAL);
729                 break;
730             case ROTATION_180 :
731                 screen->SetOrientation(Orientation::REVERSE_VERTICAL);
732                 break;
733             case ROTATION_270 :
734                 screen->SetOrientation(Orientation::REVERSE_HORIZONTAL);
735                 break;
736             default :
737                 break;
738         }
739     }
740 
GetDisplayRotation() const741     DisplayRotation SysUiController::GetDisplayRotation() const
742     {
743         auto display = DisplayManager::GetInstance().GetDefaultDisplay();
744         if (display == nullptr) {
745             LOG_E("DisplayManager init fail");
746             return DisplayRotation::ROTATION_0;
747         }
748         auto rotation = (DisplayRotation)display->GetRotation();
749         return rotation;
750     }
751 
SetDisplayRotationEnabled(bool enabled) const752     void SysUiController::SetDisplayRotationEnabled(bool enabled) const
753     {
754         ScreenManager &screenMgr = ScreenManager::GetInstance();
755         DCHECK(screenMgr);
756         screenMgr.SetScreenRotationLocked(!enabled);
757     }
758 
GetDisplaySize() const759     Point SysUiController::GetDisplaySize() const
760     {
761         auto display = DisplayManager::GetInstance().GetDefaultDisplay();
762         if (display == nullptr) {
763             LOG_E("DisplayManager init fail");
764             return {0, 0};
765         }
766         auto width = display->GetWidth();
767         auto height = display->GetHeight();
768         Point result(width, height);
769         return result;
770     }
771 
GetDisplayDensity() const772     Point SysUiController::GetDisplayDensity() const
773     {
774         auto display = DisplayManager::GetInstance().GetDefaultDisplay();
775         if (display == nullptr) {
776             LOG_E("DisplayManager init fail");
777             return {0, 0};
778         }
779         auto rate = display->GetVirtualPixelRatio();
780         Point displaySize = GetDisplaySize();
781         Point result(displaySize.px_ * rate, displaySize.py_ * rate);
782         return result;
783     }
784 
IsScreenOn() const785     bool SysUiController::IsScreenOn() const
786     {
787         DisplayManager &displayMgr = DisplayManager::GetInstance();
788         DCHECK(displayMgr);
789         auto displayId = displayMgr.GetDefaultDisplayId();
790         auto state = displayMgr.GetDisplayState(displayId);
791         return (state != DisplayState::OFF);
792     }
793 
794     class OnSaLoadCallback : public SystemAbilityLoadCallbackStub {
795     public:
OnSaLoadCallback(mutex & mutex)796         explicit OnSaLoadCallback(mutex &mutex): mutex_(mutex) {};
~OnSaLoadCallback()797         ~OnSaLoadCallback() {};
OnLoadSystemAbilitySuccess(int32_t systemAbilityId,const sptr<IRemoteObject> & remoteObject)798         void OnLoadSystemAbilitySuccess(int32_t systemAbilityId, const sptr<IRemoteObject>& remoteObject) override
799         {
800             if (systemAbilityId == OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID) {
801                 remoteObject_ = remoteObject;
802                 mutex_.unlock();
803             }
804         }
OnLoadSystemAbilityFail(int32_t systemAbilityId)805         void OnLoadSystemAbilityFail(int32_t systemAbilityId) override
806         {
807             if (systemAbilityId == OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID) {
808                 mutex_.unlock();
809             }
810         }
811 
GetSaObject()812         sptr<IRemoteObject> GetSaObject()
813         {
814             return remoteObject_;
815         }
816 
817     private:
818         mutex &mutex_;
819         sptr<IRemoteObject> remoteObject_ = nullptr;
820     };
821 
GetHidumperInfo(std::string windowId,char ** buf,size_t & len)822     void SysUiController::GetHidumperInfo(std::string windowId, char **buf, size_t &len)
823     {
824 #ifdef HIDUMPER_ENABLED
825         auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
826         if (sam == nullptr) {
827             LOG_E("Get samgr failed");
828             return;
829         }
830         auto remoteObject = sam->CheckSystemAbility(OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID);
831         if (remoteObject == nullptr) {
832             mutex lock;
833             lock.lock();
834             sptr<OnSaLoadCallback> loadCallback = new OnSaLoadCallback(lock);
835             int32_t result = sam->LoadSystemAbility(OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID, loadCallback);
836             if (result != ERR_OK) {
837                 LOG_E("Schedule LoadSystemAbility failed");
838                 return;
839             }
840             LOG_E("Schedule LoadSystemAbility succeed");
841             lock.lock();
842             remoteObject = loadCallback->GetSaObject();
843             LOG_E("LoadSystemAbility callbacked, result = %{public}s", remoteObject == nullptr ? "FAIL" : "SUCCESS");
844         }
845         if (remoteObject == nullptr) {
846             LOG_E("remoteObject is null");
847             return;
848         }
849         // run dump command
850         sptr<IDumpBroker> client = iface_cast<IDumpBroker>(remoteObject);
851         auto fd = memfd_create("dummy_file", 2);
852         ftruncate(fd, 0);
853         vector<u16string> args;
854         args.emplace_back(u"hidumper");
855         args.emplace_back(u"-s");
856         args.emplace_back(u"WindowManagerService");
857         args.emplace_back(u"-a");
858         auto winIdInUtf16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t > {}.from_bytes(windowId);
859         auto arg = u16string(u"-w ").append(winIdInUtf16).append(u" -element -c -lastpage");
860         args.emplace_back(move(arg));
861         client->Request(args, fd);
862         auto size = lseek(fd, 0, SEEK_END);
863         char *tempBuf = new char[size + 1];
864         lseek(fd, 0, SEEK_SET);
865         read(fd, tempBuf, size);
866         *buf = tempBuf;
867         len = size;
868         close(fd);
869 #else
870         *buf = nullptr;
871         len = 0;
872 #endif
873     }
874 } // namespace OHOS::uitest