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