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