• 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 <future>
17 #include "ui_model.h"
18 #include "ui_driver.h"
19 
20 namespace OHOS::uitest {
21     using namespace std;
22     using namespace nlohmann;
23 
24     class WindowCacheCompareGreater {
25     public:
operator ()(const WindowCacheModel & w1,const WindowCacheModel & w2)26         bool operator()(const WindowCacheModel &w1, const WindowCacheModel &w2)
27         {
28             if (w1.window_.actived_) {
29                 return true;
30             }
31             if (w2.window_.actived_) {
32                 return false;
33             }
34             if (w1.window_.focused_) {
35                 return true;
36             }
37             if (w2.window_.focused_) {
38                 return false;
39             }
40             return w1.window_.windowLayer_ > w2.window_.windowLayer_;
41         }
42     };
43 
44     std::unique_ptr<UiController> UiDriver::uiController_;
45 
RegisterController(std::unique_ptr<UiController> controller)46     void UiDriver::RegisterController(std::unique_ptr<UiController> controller)
47     {
48         uiController_ = move(controller);
49     }
50 
RegisterUiEventListener(std::shared_ptr<UiEventListener> listener)51     void UiDriver::RegisterUiEventListener(std::shared_ptr<UiEventListener> listener)
52     {
53         uiController_->RegisterUiEventListener(listener);
54     }
55 
CheckStatus(bool isConnected,ApiCallErr & error)56     bool UiDriver::CheckStatus(bool isConnected, ApiCallErr &error)
57     {
58         DCHECK(uiController_);
59         if (isConnected && !uiController_->IsWorkable()) {
60             LOG_W("Not connect to AAMS, try to reconnect");
61             if (!uiController_->Initialize(error)) {
62                 LOG_E("%{public}s", error.message_.c_str());
63                 return false;
64             }
65         }
66         return true;
67     }
68 
UpdateUIWindows(ApiCallErr & error,int32_t targetDisplay)69     void UiDriver::UpdateUIWindows(ApiCallErr &error, int32_t targetDisplay)
70     {
71         visitWidgets_.clear();
72         targetWidgetsIndex_.clear();
73         displayToWindowCacheMap_.clear();
74         if (!CheckStatus(true, error)) {
75             return;
76         }
77         std::map<int32_t, vector<Window>> currentDisplayAndWindowCacheMap;
78         uiController_->GetUiWindows(currentDisplayAndWindowCacheMap, targetDisplay);
79         if (currentDisplayAndWindowCacheMap.empty()) {
80             LOG_E("Get Windows Failed");
81             error = ApiCallErr(ERR_INTERNAL, "Get window nodes failed");
82         }
83         for (auto dm : currentDisplayAndWindowCacheMap) {
84             auto currentWindowVec = dm.second;
85             std::vector<WindowCacheModel> windowCacheVec;
86             for (const auto &win : currentWindowVec) {
87                 WindowCacheModel cacheModel(win);
88                 windowCacheVec.emplace_back(std::move(cacheModel));
89                 std::stringstream ss;
90                 ss << "window rect is ";
91                 ss << win.bounds_.Describe();
92                 ss << "overplay window rects are:[";
93                 for (const auto& overRect : win.invisibleBoundsVec_) {
94                     ss << overRect.Describe();
95                     ss << ", ";
96                 }
97                 ss << "]";
98                 LOG_D("window: %{public}d in display %{public}d, %{public}s",
99                       win.id_, win.displayId_, ss.str().data());
100             }
101             // actice or focus window move to top
102             std::sort(windowCacheVec.begin(), windowCacheVec.end(), WindowCacheCompareGreater());
103             displayToWindowCacheMap_.insert(make_pair(dm.first, move(windowCacheVec)));
104         }
105     }
106 
DumpWindowsInfo(const DumpOption & option,Rect & mergeBounds,nlohmann::json & childDom)107     void UiDriver::DumpWindowsInfo(const DumpOption &option, Rect& mergeBounds, nlohmann::json& childDom)
108     {
109         std::vector<WidgetMatchModel> emptyMatcher;
110         StrategyBuildParam buildParam;
111         buildParam.myselfMatcher = emptyMatcher;
112         std::unique_ptr<SelectStrategy> selectStrategy = SelectStrategy::BuildSelectStrategy(buildParam, true);
113         auto dm = displayToWindowCacheMap_.find(option.displayId_);
114         if (dm == displayToWindowCacheMap_.end()) {
115             return;
116         }
117         auto &windowCacheVec = dm->second;
118         for (auto &winCache : windowCacheVec) {
119             if (option.bundleName_ != "" && winCache.window_.bundleName_ != option.bundleName_) {
120                 LOG_D("skip window(%{public}s), it is not target window %{public}s",
121                     winCache.window_.bundleName_.data(), option.bundleName_.data());
122                 continue;
123             }
124             if (option.windowId_ != "" && winCache.window_.id_ != atoi(option.windowId_.c_str())) {
125                 LOG_D("skip window(%{public}d), it is not target window %{public}s",
126                     winCache.window_.id_, option.windowId_.data());
127                 continue;
128             }
129             visitWidgets_.clear();
130             targetWidgetsIndex_.clear();
131             if (!uiController_->GetWidgetsInWindow(winCache.window_, winCache.widgetIterator_, mode_)) {
132                 LOG_W("Get Widget from window[%{public}d] failed, skip the window", winCache.window_.id_);
133                 continue;
134             }
135             selectStrategy->LocateNode(winCache.window_, *winCache.widgetIterator_, visitWidgets_, targetWidgetsIndex_,
136                                        option);
137             nlohmann::json child = nlohmann::json();
138             if (visitWidgets_.empty()) {
139                 LOG_E("Window %{public}s has no node, skip it", winCache.window_.bundleName_.data());
140                 continue;
141             } else {
142                 DumpHandler::DumpWindowInfoToJson(visitWidgets_, child);
143             }
144             child["attributes"]["abilityName"] = winCache.window_.abilityName_;
145             child["attributes"]["bundleName"] = winCache.window_.bundleName_;
146             child["attributes"]["pagePath"] = winCache.window_.pagePath_;
147             childDom.emplace_back(child);
148             mergeBounds.left_ = std::min(mergeBounds.left_, winCache.window_.bounds_.left_);
149             mergeBounds.top_ = std::min(mergeBounds.top_, winCache.window_.bounds_.top_);
150             mergeBounds.right_ = std::max(mergeBounds.right_, winCache.window_.bounds_.right_);
151             mergeBounds.bottom_ = std::max(mergeBounds.bottom_, winCache.window_.bounds_.bottom_);
152         }
153     }
154 
DumpUiHierarchy(nlohmann::json & out,const DumpOption & option,ApiCallErr & error)155     void UiDriver::DumpUiHierarchy(nlohmann::json &out, const DumpOption &option, ApiCallErr &error)
156     {
157         UpdateUIWindows(error, option.displayId_);
158         if (error.code_ != NO_ERROR) {
159             return;
160         }
161         auto dm = displayToWindowCacheMap_.find(option.displayId_);
162         if (dm == displayToWindowCacheMap_.end()) {
163             LOG_E("Get windows id display %{public}d failed, dump error.", option.displayId_);
164             error = ApiCallErr(ERR_INTERNAL, "Get window nodes failed");
165             return;
166         }
167         nlohmann::json childDom = nlohmann::json::array();
168         Rect mergeBounds{0, 0, 0, 0};
169         DumpWindowsInfo(option, mergeBounds, childDom);
170         if (option.listWindows_) {
171             out = childDom;
172         } else {
173             nlohmann::json attrData = nlohmann::json();
174 
175             for (int i = 0; i < UiAttr::HIERARCHY; ++i) {
176                 attrData[ATTR_NAMES[i].data()] = "";
177             }
178             std::stringstream ss;
179             ss << "[" << mergeBounds.left_ << "," << mergeBounds.top_ << "]"
180                << "[" << mergeBounds.right_ << "," << mergeBounds.bottom_ << "]";
181             attrData[ATTR_NAMES[UiAttr::BOUNDS].data()] = ss.str();
182             out["attributes"] = attrData;
183             out["children"] = childDom;
184         }
185 
186         if (option.addExternAttr_) {
187             map<int32_t, string_view> elementTrees;
188             vector<char *> buffers;
189             auto &windowCacheVec = dm->second;
190             for (auto &winCache : windowCacheVec) {
191                 char *buffer = nullptr;
192                 size_t len = 0;
193                 uiController_->GetHidumperInfo(to_string(winCache.window_.id_), &buffer, len);
194                 if (buffer == nullptr) {
195                     continue;
196                 }
197                 elementTrees.insert(make_pair(winCache.window_.id_, string_view(buffer, len)));
198                 buffers.push_back(buffer);
199             }
200             DumpHandler::AddExtraAttrs(out, elementTrees, 0);
201             for (auto &buf : buffers) {
202                 delete buf;
203             }
204         }
205     }
206 
CloneFreeWidget(const Widget & from,const string & selectDesc)207     static unique_ptr<Widget> CloneFreeWidget(const Widget &from, const string &selectDesc)
208     {
209         auto clone = from.Clone(from.GetHierarchy());
210         clone->SetAttr(UiAttr::DUMMY_ATTRNAME_SELECTION, selectDesc + from.GetAttr(UiAttr::HASHCODE));
211         // save the selection desc as dummy attribute
212         return clone;
213     }
214 
ConstructSelectStrategyByRetrieve(const Widget & widget)215     static std::unique_ptr<SelectStrategy> ConstructSelectStrategyByRetrieve(const Widget &widget)
216     {
217         WidgetMatchModel attrMatch{UiAttr::HASHCODE, widget.GetAttr(UiAttr::HASHCODE), EQ};
218         StrategyBuildParam buildParam;
219         buildParam.myselfMatcher.emplace_back(attrMatch);
220         return SelectStrategy::BuildSelectStrategy(buildParam, false);
221     }
222 
GetHostApp(const Widget & widget)223     string UiDriver::GetHostApp(const Widget &widget)
224     {
225         auto winId = widget.GetAttr(UiAttr::HOST_WINDOW_ID);
226         auto displayId = widget.GetDisplayId();
227         if (winId.length() < 1) {
228             winId = "0";
229         }
230         auto dm = displayToWindowCacheMap_.find(displayId);
231         if (dm == displayToWindowCacheMap_.end()) {
232             return "";
233         }
234         auto &windowCacheVec = dm->second;
235         auto id = atoi(winId.c_str());
236         for (auto &windowCache : windowCacheVec) {
237             if (id == windowCache.window_.id_) {
238                 // If not a actived window, get all.
239                 if (windowCache.window_.actived_ == false) {
240                     return "";
241                 }
242                 return windowCache.window_.bundleName_;
243             }
244         }
245         return "";
246     }
247 
RetrieveWidget(const Widget & widget,ApiCallErr & err,bool updateUi)248     const Widget *UiDriver::RetrieveWidget(const Widget &widget, ApiCallErr &err, bool updateUi)
249     {
250         if (updateUi) {
251             UpdateUIWindows(err, widget.GetDisplayId());
252             if (err.code_ != NO_ERROR) {
253                 LOG_E("Retrieve Widget with error %{public}s", err.message_.c_str());
254                 return nullptr;
255             }
256         } else {
257             visitWidgets_.clear();
258             targetWidgetsIndex_.clear();
259         }
260         std::unique_ptr<SelectStrategy> selectStrategy = ConstructSelectStrategyByRetrieve(widget);
261         auto &windowCacheVec = displayToWindowCacheMap_.find(widget.GetDisplayId())->second;
262         for (auto &curWinCache : windowCacheVec) {
263             if (widget.GetAttr(UiAttr::HOST_WINDOW_ID) != std::to_string(curWinCache.window_.id_)) {
264                 continue;
265             }
266             selectStrategy->SetAndCalcSelectWindowRect(curWinCache.window_.bounds_,
267                                                        curWinCache.window_.invisibleBoundsVec_);
268             if (curWinCache.widgetIterator_ == nullptr) {
269                 if (!uiController_->GetWidgetsInWindow(curWinCache.window_, curWinCache.widgetIterator_, mode_)) {
270                     LOG_W("Get Widget from window[%{public}d] failed, skip the window", curWinCache.window_.id_);
271                     continue;
272                 }
273             }
274             DumpOption option;
275             selectStrategy->LocateNode(curWinCache.window_, *curWinCache.widgetIterator_, visitWidgets_,
276                                        targetWidgetsIndex_, option);
277             if (!targetWidgetsIndex_.empty()) {
278                 break;
279             }
280         }
281         stringstream msg;
282         msg << "Widget: " << widget.GetAttr(UiAttr::DUMMY_ATTRNAME_SELECTION);
283         msg << "dose not exist on current UI! Check if the UI has changed after you got the widget object";
284         if (targetWidgetsIndex_.empty()) {
285             msg << "(NoCandidates)";
286             err = ApiCallErr(ERR_COMPONENT_LOST, msg.str());
287             LOG_W("%{public}s", err.message_.c_str());
288             return nullptr;
289         }
290         DCHECK(targetWidgetsIndex_.size() == 1);
291         // confirm type
292         if (widget.GetAttr(UiAttr::TYPE) != visitWidgets_[targetWidgetsIndex_[0]].GetAttr(UiAttr::TYPE)) {
293             msg << " (CompareEqualsFailed)";
294             err = ApiCallErr(ERR_COMPONENT_LOST, msg.str());
295             LOG_W("%{public}s", err.message_.c_str());
296             return nullptr;
297         }
298         return &visitWidgets_[targetWidgetsIndex_[0]];
299     }
300 
TriggerKey(const KeyAction & key,const UiOpArgs & opt,ApiCallErr & error)301     void UiDriver::TriggerKey(const KeyAction &key, const UiOpArgs &opt, ApiCallErr &error)
302     {
303         if (!CheckStatus(false, error)) {
304             return;
305         }
306         vector<KeyEvent> events;
307         key.ComputeEvents(events, opt);
308         if (events.empty()) {
309             return;
310         }
311         uiController_->InjectKeyEventSequence(events);
312     }
313 
FindWidgets(const WidgetSelector & selector,vector<unique_ptr<Widget>> & rev,ApiCallErr & err,bool updateUi)314     void UiDriver::FindWidgets(const WidgetSelector &selector, vector<unique_ptr<Widget>> &rev,
315         ApiCallErr &err, bool updateUi)
316     {
317         UiOpArgs opt;
318         uiController_->WaitForUiSteady(opt.uiSteadyThresholdMs_, opt.waitUiSteadyMaxMs_);
319         if (updateUi) {
320             UpdateUIWindows(err, selector.GetDisplayLocator());
321             if (err.code_ != NO_ERROR) {
322                 return;
323             }
324         } else {
325             visitWidgets_.clear();
326             targetWidgetsIndex_.clear();
327         }
328         auto appLocator = selector.GetAppLocator();
329         for (auto &dm : displayToWindowCacheMap_) {
330             auto &windowCacheVec = dm.second;
331             for (auto &curWinCache : windowCacheVec) {
332                 if (appLocator != "" && curWinCache.window_.bundleName_ != appLocator) {
333                     continue;
334                 }
335                 if (curWinCache.widgetIterator_ == nullptr &&
336                     !uiController_->GetWidgetsInWindow(curWinCache.window_, curWinCache.widgetIterator_, mode_)) {
337                     continue;
338                 }
339                 selector.Select(curWinCache.window_, *curWinCache.widgetIterator_, visitWidgets_, targetWidgetsIndex_);
340                 if (!selector.IsWantMulti() && !targetWidgetsIndex_.empty()) {
341                     break;
342                 }
343                 if (!selector.IsWantMulti()) {
344                     visitWidgets_.clear();
345                     targetWidgetsIndex_.clear();
346                 }
347             }
348             if (!selector.IsWantMulti() && !targetWidgetsIndex_.empty()) {
349                 break;
350             }
351         }
352         if (targetWidgetsIndex_.empty()) {
353             LOG_W("self node not found by %{public}s", selector.Describe().data());
354             return;
355         }
356         // covert widgets to images as return value
357         uint32_t index = 0;
358         for (auto targetIndex : targetWidgetsIndex_) {
359             auto image = CloneFreeWidget(visitWidgets_[targetIndex], selector.Describe());
360             // at sometime, more than one widgets are found, add the node index to the description
361             rev.emplace_back(move(image));
362             index++;
363         }
364     }
365 
WaitForWidget(const WidgetSelector & selector,const UiOpArgs & opt,ApiCallErr & err)366     unique_ptr<Widget> UiDriver::WaitForWidget(const WidgetSelector &selector, const UiOpArgs &opt, ApiCallErr &err)
367     {
368         const uint32_t sliceMs = 20;
369         const auto startMs = GetCurrentMillisecond();
370         vector<unique_ptr<Widget>> receiver;
371         do {
372             FindWidgets(selector, receiver, err);
373             if (err.code_ != NO_ERROR) { // abort on error
374                 return nullptr;
375             }
376             if (!receiver.empty()) {
377                 return move(receiver.at(0));
378             }
379             DelayMs(sliceMs);
380         } while (GetCurrentMillisecond() - startMs < opt.waitWidgetMaxMs_);
381         return nullptr;
382     }
383 
DelayMs(uint32_t ms)384     void UiDriver::DelayMs(uint32_t ms)
385     {
386         if (ms > 0) {
387             this_thread::sleep_for(chrono::milliseconds(ms));
388         }
389     }
390 
PerformTouch(const TouchAction & touch,const UiOpArgs & opt,ApiCallErr & err)391     void UiDriver::PerformTouch(const TouchAction &touch, const UiOpArgs &opt, ApiCallErr &err)
392     {
393         if (!CheckStatus(false, err)) {
394             return;
395         }
396         PointerMatrix events;
397         touch.Decompose(events, opt);
398         if (events.Empty()) {
399             return;
400         }
401         uiController_->InjectTouchEventSequence(events);
402     }
403 
PerformMouseAction(const MouseAction & touch,const UiOpArgs & opt,ApiCallErr & err)404     void UiDriver::PerformMouseAction(const MouseAction &touch, const UiOpArgs &opt, ApiCallErr &err)
405     {
406         if (!CheckStatus(false, err)) {
407             return;
408         }
409         vector<MouseEvent> events;
410         touch.Decompose(events, opt);
411         if (events.empty()) {
412             return;
413         }
414         uiController_->InjectMouseEventSequence(events);
415     }
416 
TakeScreenCap(int32_t fd,ApiCallErr & err,Rect rect,int32_t displayId)417     void UiDriver::TakeScreenCap(int32_t fd, ApiCallErr &err, Rect rect, int32_t displayId)
418     {
419         if (!CheckStatus(false, err)) {
420             return;
421         }
422         stringstream errorRecv;
423         if (!uiController_->TakeScreenCap(fd, errorRecv, displayId, rect)) {
424             string errStr = errorRecv.str();
425             LOG_W("ScreenCap failed: %{public}s", errStr.c_str());
426             if (errStr.find("File opening failed") == 0) {
427                 err = ApiCallErr(ERR_INVALID_INPUT, "Invalid save path or permission denied");
428             } else {
429                 err = ApiCallErr(ERR_INTERNAL, errStr);
430             }
431             LOG_W("ScreenCap failed: %{public}s", errorRecv.str().c_str());
432         } else {
433             LOG_D("ScreenCap successed");
434         }
435     }
436 
FindWindow(function<bool (const Window &)> matcher,ApiCallErr & err)437     unique_ptr<Window> UiDriver::FindWindow(function<bool(const Window &)> matcher, ApiCallErr &err)
438     {
439         UpdateUIWindows(err);
440         if (err.code_ != NO_ERROR) {
441             return nullptr;
442         }
443         for (auto &dm : displayToWindowCacheMap_) {
444             auto &windowCacheVec = dm.second;
445             for (auto &windowCache : windowCacheVec) {
446                 if (matcher(windowCache.window_)) {
447                     auto clone = make_unique<Window>(0);
448                     *clone = windowCache.window_; // copy construct
449                     return clone;
450                 }
451             }
452         }
453         return nullptr;
454     }
455 
RetrieveWindow(const Window & window,ApiCallErr & err)456     const Window *UiDriver::RetrieveWindow(const Window &window, ApiCallErr &err)
457     {
458         UpdateUIWindows(err, window.displayId_);
459         if (err.code_ != NO_ERROR) {
460             return nullptr;
461         }
462         auto dm = displayToWindowCacheMap_.find(window.displayId_);
463         auto &windowCacheVec = dm->second;
464         for (auto &winCache : windowCacheVec) {
465             if (winCache.window_.id_ != window.id_) {
466                 continue;
467             }
468             return &winCache.window_;
469         }
470         stringstream msg;
471         msg << "Display " << window.displayId_;
472         msg << "Window " << window.id_;
473         msg << "dose not exist on current UI! Check if the UI has changed after you got the window object";
474         err = ApiCallErr(ERR_COMPONENT_LOST, msg.str());
475         LOG_W("%{public}s", err.message_.c_str());
476         return nullptr;
477     }
478 
SetDisplayRotation(DisplayRotation rotation,ApiCallErr & error)479     void UiDriver::SetDisplayRotation(DisplayRotation rotation, ApiCallErr &error)
480     {
481         if (!CheckStatus(false, error)) {
482             return;
483         }
484         uiController_->SetDisplayRotation(rotation);
485     }
486 
GetDisplayRotation(ApiCallErr & error,int32_t displayId)487     DisplayRotation UiDriver::GetDisplayRotation(ApiCallErr &error, int32_t displayId)
488     {
489         if (!CheckStatus(false, error)) {
490             return ROTATION_0;
491         }
492         return uiController_->GetDisplayRotation(displayId);
493     }
494 
SetDisplayRotationEnabled(bool enabled,ApiCallErr & error)495     void UiDriver::SetDisplayRotationEnabled(bool enabled, ApiCallErr &error)
496     {
497         if (!CheckStatus(false, error)) {
498             return;
499         }
500         uiController_->SetDisplayRotationEnabled(enabled);
501     }
502 
WaitForUiSteady(uint32_t idleThresholdMs,uint32_t timeoutSec,ApiCallErr & error)503     bool UiDriver::WaitForUiSteady(uint32_t idleThresholdMs, uint32_t timeoutSec, ApiCallErr &error)
504     {
505         if (!CheckStatus(false, error)) {
506             return false;
507         }
508         return uiController_->WaitForUiSteady(idleThresholdMs, timeoutSec);
509     }
510 
WakeUpDisplay(ApiCallErr & error)511     void UiDriver::WakeUpDisplay(ApiCallErr &error)
512     {
513         if (!CheckStatus(false, error)) {
514             return;
515         }
516         if (uiController_->IsScreenOn()) {
517             return;
518         } else {
519             LOG_D("screen is off, turn it on");
520             UiOpArgs uiOpArgs;
521             this->TriggerKey(Power(), uiOpArgs, error);
522         }
523     }
524 
GetDisplaySize(ApiCallErr & error,int32_t displayId)525     Point UiDriver::GetDisplaySize(ApiCallErr &error, int32_t displayId)
526     {
527         if (!CheckStatus(false, error)) {
528             return Point(0, 0);
529         }
530         return uiController_->GetDisplaySize(displayId);
531     }
532 
GetDisplayDensity(ApiCallErr & error,int32_t displayId)533     Point UiDriver::GetDisplayDensity(ApiCallErr &error, int32_t displayId)
534     {
535         if (!CheckStatus(false, error)) {
536             return Point(0, 0);
537         }
538         return uiController_->GetDisplayDensity(displayId);
539     }
540 
TextToKeyEvents(string_view text,std::vector<KeyEvent> & events,ApiCallErr & error)541     bool UiDriver::TextToKeyEvents(string_view text, std::vector<KeyEvent> &events, ApiCallErr &error)
542     {
543         if (!CheckStatus(false, error)) {
544             return false;
545         }
546         static constexpr uint32_t typeCharTimeMs = 50;
547         if (!text.empty()) {
548             vector<char> chars(text.begin(), text.end()); // decompose to sing-char input sequence
549             vector<pair<int32_t, int32_t>> keyCodes;
550             for (auto ch : chars) {
551                 int32_t code = KEYCODE_NONE;
552                 int32_t ctrlCode = KEYCODE_NONE;
553                 if (!uiController_->GetCharKeyCode(ch, code, ctrlCode)) {
554                     return false;
555                 }
556                 keyCodes.emplace_back(make_pair(code, ctrlCode));
557             }
558             for (auto &pair : keyCodes) {
559                 if (pair.second != KEYCODE_NONE) {
560                     events.emplace_back(KeyEvent {ActionStage::DOWN, pair.second, 0});
561                 }
562                 events.emplace_back(KeyEvent {ActionStage::DOWN, pair.first, typeCharTimeMs});
563                 if (pair.second != KEYCODE_NONE) {
564                     events.emplace_back(KeyEvent {ActionStage::UP, pair.second, 0});
565                 }
566                 events.emplace_back(KeyEvent {ActionStage::UP, pair.first, 0});
567             }
568         }
569         return true;
570     }
571 
InputText(string_view text,ApiCallErr & error)572     void UiDriver::InputText(string_view text, ApiCallErr &error)
573     {
574         vector<KeyEvent> events;
575         UiOpArgs uiOpArgs;
576         if (!text.empty()) {
577             constexpr auto maxKeyEventCounts = 200;
578             if (text.length() < maxKeyEventCounts && TextToKeyEvents(text, events, error)) {
579                 LOG_D("inputText by Keycode");
580                 auto keyActionForInput = KeysForwarder(events);
581                 TriggerKey(keyActionForInput, uiOpArgs, error);
582             } else {
583                 uiController_->PutTextToClipboard(text);
584                 LOG_D("inputText by pasteBoard");
585                 auto actionForPatse = CombinedKeys(KEYCODE_CTRL, KEYCODE_V, KEYCODE_NONE);
586                 TriggerKey(actionForPatse, uiOpArgs, error);
587             }
588         }
589     }
590 
PerformTouchPadAction(const TouchPadAction & touch,const UiOpArgs & opt,ApiCallErr & error)591     void UiDriver::PerformTouchPadAction(const TouchPadAction &touch, const UiOpArgs &opt, ApiCallErr &error)
592     {
593         if (!CheckStatus(false, error)) {
594             return;
595         }
596         if (!uiController_->IsTouchPadExist()) {
597             error = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "This device can not support this action");
598             return;
599         }
600         vector<TouchPadEvent> events;
601         touch.Decompose(events, opt, uiController_->GetDisplaySize(0));
602         if (events.empty()) {
603             return;
604         }
605         uiController_->InjectTouchPadEventSequence(events);
606     }
607 
PerformPenTouch(const TouchAction & touch,const UiOpArgs & opt,ApiCallErr & err)608     void UiDriver::PerformPenTouch(const TouchAction &touch, const UiOpArgs &opt, ApiCallErr &err)
609     {
610         if (!CheckStatus(false, err)) {
611             return;
612         }
613         if (opt.touchPressure_ < 0 || opt.touchPressure_ > 1) {
614             err = ApiCallErr(ERR_INVALID_INPUT, "Pressure must ranges form 0 to 1");
615             return;
616         }
617         PointerMatrix events;
618         touch.Decompose(events, opt);
619         PointerMatrix eventsInPen(1, events.GetSteps() + INDEX_TWO);
620         eventsInPen.SetTouchPressure(opt.touchPressure_);
621         events.ConvertToPenEvents(eventsInPen);
622         if (eventsInPen.Empty()) {
623             return;
624         }
625         uiController_->InjectTouchEventSequence(eventsInPen);
626     }
627 
SetAamsWorkMode(const AamsWorkMode mode)628     void UiDriver::SetAamsWorkMode(const AamsWorkMode mode)
629     {
630         mode_ = mode;
631     }
632 } // namespace OHOS::uitest
633