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