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 <sstream>
17 #include <unistd.h>
18 #include "ui_driver.h"
19 #include "widget_operator.h"
20 #include "window_operator.h"
21 #include "ui_controller.h"
22 #include "frontend_api_handler.h"
23
24 namespace OHOS::uitest {
25 using namespace std;
26 using namespace nlohmann;
27 using namespace nlohmann::detail;
28
29 class UIEventObserver : public BackendClass {
30 public:
UIEventObserver()31 UIEventObserver() {};
32 const FrontEndClassDef &GetFrontendClassDef() const override
33 {
34 return UI_EVENT_OBSERVER_DEF;
35 };
36 };
37
38 class UiEventFowarder : public UiEventListener {
39 public:
UiEventFowarder()40 UiEventFowarder() {};
41
IncRef(const string &ref)42 void IncRef(const string &ref)
43 {
44 auto find = refCountMap_.find(ref);
45 if (find != refCountMap_.end()) {
46 find->second++;
47 } else {
48 refCountMap_.insert(make_pair(ref, 1));
49 }
50 }
51
DecAndGetRef(const string &ref)52 uint32_t DecAndGetRef(const string &ref)
53 {
54 auto find = refCountMap_.find(ref);
55 if (find != refCountMap_.end()) {
56 find->second--;
57 if (find->second == 0) {
58 refCountMap_.erase(find);
59 return 0;
60 }
61 return find->second;
62 }
63 return 0;
64 }
65
66 void OnEvent(const std::string &event, const UiEventSourceInfo &source) override
67 {
68 const auto &server = FrontendApiServer::Get();
69 json uiElementInfo;
70 uiElementInfo["bundleName"] = source.bundleName;
71 uiElementInfo["type"] = source.type;
72 uiElementInfo["text"] = source.text;
73 auto count = callBackInfos_.count(event);
74 size_t index = 0;
75 while (index < count) {
76 auto find = callBackInfos_.find(event);
77 if (find == callBackInfos_.end()) {
78 return;
79 }
80 const auto &observerRef = find->second.first;
81 const auto &callbackRef = find->second.second;
82 ApiCallInfo in;
83 ApiReplyInfo out;
84 in.apiId_ = "UIEventObserver.once";
85 in.callerObjRef_ = observerRef;
86 in.paramList_.push_back(uiElementInfo);
87 in.paramList_.push_back(callbackRef);
88 in.paramList_.push_back(DecAndGetRef(observerRef) == 0);
89 in.paramList_.push_back(DecAndGetRef(callbackRef) == 0);
90 server.Callback(in, out);
91 callBackInfos_.erase(find);
92 index++;
93 }
94 }
95
AddCallbackInfo(const string &&event, const string &observerRef, const string &&cbRef)96 void AddCallbackInfo(const string &&event, const string &observerRef, const string &&cbRef)
97 {
98 auto count = callBackInfos_.count(event);
99 auto find = callBackInfos_.find(event);
100 for (size_t index = 0; index < count; index++) {
101 if (find != callBackInfos_.end()) {
102 if (find->second.first == observerRef && find->second.second == cbRef) {
103 return;
104 }
105 find++;
106 }
107 }
108 callBackInfos_.insert(make_pair(event, make_pair(observerRef, cbRef)));
109 IncRef(observerRef);
110 IncRef(cbRef);
111 }
112
113 private:
114 multimap<string, pair<string, string>> callBackInfos_;
115 map<string, int> refCountMap_;
116 };
117
118 /** API argument type list map.*/
119 static multimap<string, pair<vector<string>, size_t>> sApiArgTypesMap;
120
ParseMethodSignature(string_view signature, vector<string> &types, size_t &defArg)121 static void ParseMethodSignature(string_view signature, vector<string> &types, size_t &defArg)
122 {
123 int charIndex = 0;
124 constexpr size_t BUF_LEN = 32;
125 char buf[BUF_LEN];
126 size_t tokenLen = 0;
127 size_t defArgCount = 0;
128 string token;
129 for (char ch : signature) {
130 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
131 buf[tokenLen++] = ch;
132 } else if (ch == '?') {
133 defArgCount++;
134 } else if (ch == ',' || ch == '?' || ch == ')') {
135 if (tokenLen > 0) {
136 token = string_view(buf, tokenLen);
137 DCHECK(find(DATA_TYPE_SCOPE.begin(), DATA_TYPE_SCOPE.end(), token) != DATA_TYPE_SCOPE.end());
138 types.emplace_back(token);
139 }
140 tokenLen = 0; // consume token and reset buffer
141 if (ch == ')') {
142 // add return value type to the end of types.
143 string retType = string(signature.substr(charIndex + 2));
144 types.emplace_back(retType);
145 break; // end parsing
146 }
147 }
148 charIndex++;
149 }
150 defArg = defArgCount;
151 }
152
153 /** Parse frontend method definitions to collect type information.*/
ParseFrontendMethodsSignature()154 static void ParseFrontendMethodsSignature()
155 {
156 for (auto classDef : FRONTEND_CLASS_DEFS) {
157 LOG_D("parse class %{public}s", string(classDef->name_).c_str());
158 if (classDef->methods_ == nullptr || classDef->methodCount_ <= 0) {
159 continue;
160 }
161 for (size_t idx = 0; idx < classDef->methodCount_; idx++) {
162 auto methodDef = classDef->methods_[idx];
163 auto paramTypes = vector<string>();
164 size_t hasDefaultArg = 0;
165 ParseMethodSignature(methodDef.signature_, paramTypes, hasDefaultArg);
166 sApiArgTypesMap.insert(make_pair(string(methodDef.name_), make_pair(paramTypes, hasDefaultArg)));
167 }
168 }
169 }
170
ParseExtensionMethodsSignature()171 static void ParseExtensionMethodsSignature()
172 {
173 auto paramTypes = vector<string>();
174 paramTypes.push_back("");
175 string extension = "Component.getAllProperties";
176 sApiArgTypesMap.insert(make_pair(extension, make_pair(paramTypes, 0)));
177 }
178
GetClassName(const string &apiName, char splitter)179 static string GetClassName(const string &apiName, char splitter)
180 {
181 auto classNameLen = apiName.find(splitter);
182 if (classNameLen == std::string::npos) {
183 return "";
184 }
185 return apiName.substr(0, classNameLen);
186 }
187
CheckAndDoApiMapping(string_view apiName, char splitter, const map<string, string> &apiMap)188 static string CheckAndDoApiMapping(string_view apiName, char splitter, const map<string, string> &apiMap)
189 {
190 string output = string(apiName);
191 auto classNameLen = output.find(splitter);
192 if (classNameLen == std::string::npos) {
193 return output;
194 }
195 string className = output.substr(0, classNameLen);
196 auto result = apiMap.find(className);
197 if (result == apiMap.end()) {
198 return output;
199 }
200 auto specialMapItem = apiMap.find(output);
201 if (specialMapItem != apiMap.end()) {
202 output = specialMapItem->second;
203 } else {
204 output.replace(0, classNameLen, result->second);
205 }
206 LOG_D("original className: %{public}s, modified to: %{public}s", className.c_str(), output.c_str());
207 return output;
208 }
209
FrontendApiServer()210 FrontendApiServer::FrontendApiServer()
211 {
212 old2NewApiMap_["By"] = "On";
213 old2NewApiMap_["UiDriver"] = "Driver";
214 old2NewApiMap_["UiComponent"] = "Component";
215 old2NewApiMap_["By.id"] = "On.accessibilityId";
216 old2NewApiMap_["By.key"] = "On.id";
217 old2NewApiMap_["UiComponent.getId"] = "Component.getAccessibilityId";
218 old2NewApiMap_["UiComponent.getKey"] = "Component.getId";
219 old2NewApiMap_["UiWindow.isActived"] = "UiWindow.isActive";
220 new2OldApiMap_["On"] = "By" ;
221 new2OldApiMap_["Driver"] = "UiDriver" ;
222 new2OldApiMap_["Component"] = "UiComponent" ;
223 }
224
225 /**
226 * map api8 old api call to new api.
227 * return old api name if it's an old api call.
228 * return empty string if it's a new api call.
229 */
230 static const std::map<ErrCode, std::vector<ErrCode>> ErrCodeMap = {
231 /**Correspondence between old and new error codes*/
232 {NO_ERROR, {NO_ERROR}},
233 {ERR_COMPONENT_LOST, {WIDGET_LOST, WINDOW_LOST}},
234 {ERR_NO_SYSTEM_CAPABILITY, {USAGE_ERROR}},
235 {ERR_INTERNAL, {INTERNAL_ERROR}},
236 {ERR_INITIALIZE_FAILED, {USAGE_ERROR}},
237 {ERR_INVALID_INPUT, {USAGE_ERROR}},
238 {ERR_ASSERTION_FAILED, {ASSERTION_FAILURE}},
239 {ERR_OPERATION_UNSUPPORTED, {INTERNAL_ERROR}},
240 {ERR_API_USAGE, {INTERNAL_ERROR}},
241 };
242
ApiMapPre(ApiCallInfo &inModifier) const243 string FrontendApiServer::ApiMapPre(ApiCallInfo &inModifier) const
244 {
245 // 1. map method name
246 const string &className = GetClassName(inModifier.apiId_, '.');
247 const auto result = old2NewApiMap_.find(className);
248 if (result == old2NewApiMap_.end()) {
249 auto iter = old2NewApiMap_.find(inModifier.apiId_);
250 if (iter != old2NewApiMap_.end()) {
251 LOG_D("original api:%{public}s, modified to:%{public}s", inModifier.apiId_.c_str(),
252 iter->second.c_str());
253 inModifier.apiId_ = iter->second;
254 }
255 return "";
256 }
257 string oldApiName = inModifier.apiId_;
258 inModifier.apiId_ = CheckAndDoApiMapping(inModifier.apiId_, '.', old2NewApiMap_);
259 LOG_D("Modify call name to %{public}s", inModifier.apiId_.c_str());
260 // 2. map callerObjRef
261 if (inModifier.callerObjRef_.find(className) == 0) {
262 inModifier.callerObjRef_.replace(0, className.length(), result->second);
263 LOG_D("Modify callobjref to %{public}s", inModifier.callerObjRef_.c_str());
264 }
265 // 3. map parameters
266 // find method signature of old api
267 const auto find = sApiArgTypesMap.find(oldApiName);
268 if (find == sApiArgTypesMap.end()) {
269 return oldApiName;
270 }
271 const auto &argTypes = find->second.first;
272 size_t argCount = inModifier.paramList_.size();
273 if (argTypes.size() - 1 < argCount) {
274 // parameter number invalid
275 return oldApiName;
276 }
277 for (size_t i = 0; i < argCount; i++) {
278 auto &argItem = inModifier.paramList_.at(i);
279 const string &argType = argTypes.at(i);
280 if (argType != "string" && argItem.type() == value_t::string) {
281 argItem = CheckAndDoApiMapping(argItem.get<string>(), '#', old2NewApiMap_);
282 }
283 }
284 return oldApiName;
285 }
286
ErrCodeMapping(ApiCallErr &apiErr)287 static void ErrCodeMapping(ApiCallErr &apiErr)
288 {
289 ErrCode ec = apiErr.code_;
290 auto msg = apiErr.message_;
291 auto findCode = ErrCodeMap.find(ec);
292 if (findCode != ErrCodeMap.end() && !findCode->second.empty()) {
293 apiErr = ApiCallErr(findCode->second.at(0), msg);
294 }
295 }
296
297 /** map new error code and api Object to old error code and api Object. */
ApiMapPost(const string &oldApiName, ApiReplyInfo &out) const298 void FrontendApiServer::ApiMapPost(const string &oldApiName, ApiReplyInfo &out) const
299 {
300 json &value = out.resultValue_;
301 const auto type = value.type();
302 // 1. error code conversion
303 ErrCodeMapping(out.exception_);
304 // 2. ret value conversion
305 const auto find = sApiArgTypesMap.find(oldApiName);
306 if (find == sApiArgTypesMap.end()) {
307 return;
308 }
309 string &retType = find->second.first.back();
310 if ((retType == "string") || (retType == "[string]")) {
311 return;
312 }
313 if (type == value_t::string) {
314 value = CheckAndDoApiMapping(value.get<string>(), '#', new2OldApiMap_);
315 } else if (type == value_t::array) {
316 for (auto &item : value) {
317 if (item.type() == value_t::string) {
318 item = CheckAndDoApiMapping(item.get<string>(), '#', new2OldApiMap_);
319 }
320 }
321 }
322 }
323
Get()324 FrontendApiServer &FrontendApiServer::Get()
325 {
326 static FrontendApiServer singleton;
327 return singleton;
328 }
329
AddHandler(string_view apiId, ApiInvokeHandler handler)330 void FrontendApiServer::AddHandler(string_view apiId, ApiInvokeHandler handler)
331 {
332 if (handler == nullptr) {
333 return;
334 }
335 handlers_.insert(make_pair(apiId, handler));
336 }
337
SetCallbackHandler(ApiInvokeHandler handler)338 void FrontendApiServer::SetCallbackHandler(ApiInvokeHandler handler)
339 {
340 callbackHandler_ = handler;
341 }
342
Callback(const ApiCallInfo& in, ApiReplyInfo& out) const343 void FrontendApiServer::Callback(const ApiCallInfo& in, ApiReplyInfo& out) const
344 {
345 if (callbackHandler_ == nullptr) {
346 out.exception_ = ApiCallErr(ERR_INTERNAL, "No callback handler set!");
347 return;
348 }
349 callbackHandler_(in, out);
350 }
351
HasHandlerFor(std::string_view apiId) const352 bool FrontendApiServer::HasHandlerFor(std::string_view apiId) const
353 {
354 string apiIdstr = CheckAndDoApiMapping(apiId, '.', old2NewApiMap_);
355 return handlers_.find(apiIdstr) != handlers_.end();
356 }
357
RemoveHandler(string_view apiId)358 void FrontendApiServer::RemoveHandler(string_view apiId)
359 {
360 handlers_.erase(string(apiId));
361 }
362
AddCommonPreprocessor(string_view name, ApiInvokeHandler processor)363 void FrontendApiServer::AddCommonPreprocessor(string_view name, ApiInvokeHandler processor)
364 {
365 if (processor == nullptr) {
366 return;
367 }
368 commonPreprocessors_.insert(make_pair(name, processor));
369 }
370
RemoveCommonPreprocessor(string_view name)371 void FrontendApiServer::RemoveCommonPreprocessor(string_view name)
372 {
373 commonPreprocessors_.erase(string(name));
374 }
375
Call(const ApiCallInfo &in, ApiReplyInfo &out) const376 void FrontendApiServer::Call(const ApiCallInfo &in, ApiReplyInfo &out) const
377 {
378 LOG_I("Begin to invoke api '%{public}s', '%{public}s'", in.apiId_.data(), in.paramList_.dump().data());
379 auto call = in;
380 // initialize method signature
381 if (sApiArgTypesMap.empty()) {
382 ParseFrontendMethodsSignature();
383 ParseExtensionMethodsSignature();
384 }
385 string oldApiName = ApiMapPre(call);
386 auto find = handlers_.find(call.apiId_);
387 if (find == handlers_.end()) {
388 out.exception_ = ApiCallErr(ERR_INTERNAL, "No handler found for api '" + call.apiId_ + "'");
389 return;
390 }
391 try {
392 for (auto &[name, processor] : commonPreprocessors_) {
393 processor(call, out);
394 if (out.exception_.code_ != NO_ERROR) {
395 out.exception_.message_ = "(PreProcessing: " + name + ")" + out.exception_.message_;
396 if (oldApiName.length() > 0) {
397 ApiMapPost(oldApiName, out);
398 }
399 return; // error during pre-processing, abort
400 }
401 }
402 } catch (std::exception &ex) {
403 out.exception_ = ApiCallErr(ERR_INTERNAL, "Preprocessor failed: " + string(ex.what()));
404 }
405 try {
406 find->second(call, out);
407 } catch (std::exception &ex) {
408 // catch possible json-parsing error
409 out.exception_ = ApiCallErr(ERR_INTERNAL, "Handler failed: " + string(ex.what()));
410 }
411 if (oldApiName.length() > 0) {
412 ApiMapPost(oldApiName, out);
413 }
414 }
415
ApiTransact(const ApiCallInfo &in, ApiReplyInfo &out)416 void ApiTransact(const ApiCallInfo &in, ApiReplyInfo &out)
417 {
418 LOG_I("Begin to invoke api '%{public}s', '%{public}s'", in.apiId_.data(), in.paramList_.dump().data());
419 FrontendApiServer::Get().Call(in, out);
420 }
421
422 /** Backend objects cache.*/
423 static map<string, unique_ptr<BackendClass>> sBackendObjects;
424 /** UiDriver binding map.*/
425 static map<string, string> sDriverBindingMap;
426
427
428 #define CHECK_CALL_ARG(condition, code, message, error) \
429 if (!(condition)) { \
430 error = ApiCallErr((code), (message)); \
431 return; \
432 }
433
434 /** Check if the json value represents and illegal data of expected type.*/
CheckCallArgType(string_view expect, const json &value, bool isDefAgc, ApiCallErr &error)435 static void CheckCallArgType(string_view expect, const json &value, bool isDefAgc, ApiCallErr &error)
436 {
437 const auto type = value.type();
438 if (isDefAgc && type == value_t::null) {
439 return;
440 }
441 const auto isInteger = type == value_t::number_integer || type == value_t::number_unsigned;
442 auto begin0 = FRONTEND_CLASS_DEFS.begin();
443 auto end0 = FRONTEND_CLASS_DEFS.end();
444 auto begin1 = FRONTEND_JSON_DEFS.begin();
445 auto end1 = FRONTEND_JSON_DEFS.end();
446 auto find0 = find_if(begin0, end0, [&expect](const FrontEndClassDef *def) { return def->name_ == expect; });
447 auto find1 = find_if(begin1, end1, [&expect](const FrontEndJsonDef *def) { return def->name_ == expect; });
448 if (expect == "int") {
449 CHECK_CALL_ARG(isInteger, ERR_INVALID_INPUT, "Expect integer", error);
450 if (atoi(value.dump().c_str()) < 0) {
451 error = ApiCallErr(ERR_INVALID_INPUT, "Expect integer which cannot be less than 0");
452 return;
453 }
454 } else if (expect == "float") {
455 CHECK_CALL_ARG(isInteger || type == value_t::number_float, ERR_INVALID_INPUT, "Expect float", error);
456 } else if (expect == "bool") {
457 CHECK_CALL_ARG(type == value_t::boolean, ERR_INVALID_INPUT, "Expect boolean", error);
458 } else if (expect == "string") {
459 CHECK_CALL_ARG(type == value_t::string, ERR_INVALID_INPUT, "Expect string", error);
460 } else if (find0 != end0) {
461 CHECK_CALL_ARG(type == value_t::string, ERR_INVALID_INPUT, "Expect " + string(expect), error);
462 const auto findRef = sBackendObjects.find(value.get<string>());
463 CHECK_CALL_ARG(findRef != sBackendObjects.end(), ERR_INTERNAL, "Bad object ref", error);
464 } else if (find1 != end1) {
465 CHECK_CALL_ARG(type == value_t::object, ERR_INVALID_INPUT, "Expect " + string(expect), error);
466 auto copy = value;
467 for (size_t idx = 0; idx < (*find1)->propCount_; idx++) {
468 auto def = (*find1)->props_ + idx;
469 const auto propName = string(def->name_);
470 if (!value.contains(propName)) {
471 CHECK_CALL_ARG(!(def->required_), ERR_INVALID_INPUT, "Missing property " + propName, error);
472 continue;
473 }
474 copy.erase(propName);
475 // check json property value type recursive
476 CheckCallArgType(def->type_, value[propName], !def->required_, error);
477 if (error.code_ != NO_ERROR) {
478 error.message_ = "Illegal value of property '" + propName + "': " + error.message_;
479 return;
480 }
481 }
482 CHECK_CALL_ARG(copy.empty(), ERR_INVALID_INPUT, "Illegal property of " + string(expect), error);
483 } else {
484 CHECK_CALL_ARG(false, ERR_INTERNAL, "Unknown target type " + string(expect), error);
485 }
486 }
487
488 /** Checks ApiCallInfo data, deliver exception and abort invocation if check fails.*/
APiCallInfoChecker(const ApiCallInfo &in, ApiReplyInfo &out)489 static void APiCallInfoChecker(const ApiCallInfo &in, ApiReplyInfo &out)
490 {
491 auto count = sApiArgTypesMap.count(in.apiId_);
492 // return nullptr by default
493 out.resultValue_ = nullptr;
494 auto find = sApiArgTypesMap.find(in.apiId_);
495 size_t index = 0;
496 while (index < count) {
497 if (find == sApiArgTypesMap.end()) {
498 return;
499 }
500 bool checkArgNum = false;
501 bool checkArgType = true;
502 out.exception_ = {NO_ERROR, "No Error"};
503 auto &types = find->second.first;
504 auto argSupportDefault = find->second.second;
505 // check argument count.(last item of "types" is return value type)
506 auto maxArgc = types.size() - 1;
507 auto minArgc = maxArgc - argSupportDefault;
508 auto argc = in.paramList_.size();
509 checkArgNum = argc <= maxArgc && argc >= minArgc;
510 if (!checkArgNum) {
511 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Illegal argument count");
512 ++find;
513 ++index;
514 continue;
515 }
516 // check argument type
517 for (size_t idx = 0; idx < argc; idx++) {
518 auto isDefArg = (idx >= minArgc) ? true : false;
519 CheckCallArgType(types.at(idx), in.paramList_.at(idx), isDefArg, out.exception_);
520 if (out.exception_.code_ != NO_ERROR) {
521 out.exception_.message_ = "Check arg" + to_string(idx) + " failed: " + out.exception_.message_;
522 checkArgType = false;
523 break;
524 }
525 }
526 if (checkArgType) {
527 return;
528 }
529 ++find;
530 ++index;
531 }
532 }
533
534 /** Store the backend object and return the reference-id.*/
StoreBackendObject(unique_ptr<BackendClass> ptr, string_view ownerRef = �)535 static string StoreBackendObject(unique_ptr<BackendClass> ptr, string_view ownerRef = "")
536 {
537 static map<string, uint32_t> sObjectCounts;
538 DCHECK(ptr != nullptr);
539 const auto typeName = string(ptr->GetFrontendClassDef().name_);
540 auto find = sObjectCounts.find(typeName);
541 uint32_t index = 0;
542 if (find != sObjectCounts.end()) {
543 index = find->second;
544 }
545 auto ref = typeName + "#" + to_string(index);
546 sObjectCounts[typeName] = index + 1;
547 sBackendObjects[ref] = move(ptr);
548 if (!ownerRef.empty()) {
549 DCHECK(sBackendObjects.find(string(ownerRef)) != sBackendObjects.end());
550 sDriverBindingMap[ref] = ownerRef;
551 }
552 return ref;
553 }
554
555 /** Retrieve the stored backend object by reference-id.*/
556 template <typename T, typename = enable_if<is_base_of_v<BackendClass, T>>>
GetBackendObject(string_view ref)557 static T &GetBackendObject(string_view ref)
558 {
559 auto find = sBackendObjects.find(string(ref));
560 DCHECK(find != sBackendObjects.end() && find->second != nullptr);
561 return *(reinterpret_cast<T *>(find->second.get()));
562 }
563
GetBoundUiDriver(string_view ref)564 static UiDriver &GetBoundUiDriver(string_view ref)
565 {
566 auto find0 = sDriverBindingMap.find(string(ref));
567 DCHECK(find0 != sDriverBindingMap.end());
568 auto find1 = sBackendObjects.find(find0->second);
569 DCHECK(find1 != sBackendObjects.end() && find1->second != nullptr);
570 return *(reinterpret_cast<UiDriver *>(find1->second.get()));
571 }
572
573 /** Delete stored backend objects.*/
BackendObjectsCleaner(const ApiCallInfo &in, ApiReplyInfo &out)574 static void BackendObjectsCleaner(const ApiCallInfo &in, ApiReplyInfo &out)
575 {
576 stringstream ss("Deleted objects[");
577 DCHECK(in.paramList_.type() == value_t::array);
578 for (const auto &item : in.paramList_) {
579 DCHECK(item.type() == value_t::string); // must be objRef
580 const auto ref = item.get<string>();
581 auto findBinding = sDriverBindingMap.find(ref);
582 if (findBinding != sDriverBindingMap.end()) {
583 sDriverBindingMap.erase(findBinding);
584 }
585 auto findObject = sBackendObjects.find(ref);
586 if (findObject == sBackendObjects.end()) {
587 LOG_W("No such object living: %{public}s", ref.c_str());
588 continue;
589 }
590 sBackendObjects.erase(findObject);
591 ss << ref << ",";
592 }
593 ss << "]";
594 LOG_D("%{public}s", ss.str().c_str());
595 }
596
ReadCallArg(const ApiCallInfo &in, size_t index)597 template <typename T> static T ReadCallArg(const ApiCallInfo &in, size_t index)
598 {
599 DCHECK(in.paramList_.type() == value_t::array);
600 DCHECK(index <= in.paramList_.size());
601 return in.paramList_.at(index).get<T>();
602 }
603
ReadCallArg(const ApiCallInfo &in, size_t index, T defValue)604 template <typename T> static T ReadCallArg(const ApiCallInfo &in, size_t index, T defValue)
605 {
606 DCHECK(in.paramList_.type() == value_t::array);
607 if (index >= in.paramList_.size()) {
608 return defValue;
609 }
610 auto type = in.paramList_.at(index).type();
611 if (type == value_t::null) {
612 return defValue;
613 } else {
614 return in.paramList_.at(index).get<T>();
615 }
616 }
617
GenericOnAttrBuilder(const ApiCallInfo &in, ApiReplyInfo &out)618 template <UiAttr kAttr, typename T> static void GenericOnAttrBuilder(const ApiCallInfo &in, ApiReplyInfo &out)
619 {
620 // always create and return a new selector
621 auto selector = make_unique<WidgetSelector>();
622 if (in.callerObjRef_ != REF_SEED_ON) { // copy-construct from the caller if it's not seed
623 *selector = GetBackendObject<WidgetSelector>(in.callerObjRef_);
624 }
625 string testValue = "";
626 if constexpr (std::is_same<string, T>::value) {
627 testValue = ReadCallArg<string>(in, INDEX_ZERO);
628 } else if constexpr (std::is_same<bool, T>::value) { // bool testValue can be defaulted to true
629 testValue = ReadCallArg<bool>(in, INDEX_ZERO, true) ? "true" : "false";
630 } else {
631 testValue = to_string(ReadCallArg<T>(in, INDEX_ZERO));
632 }
633 auto matchPattern = ReadCallArg<uint8_t>(in, INDEX_ONE, ValueMatchPattern::EQ); // match pattern argument
634 auto matcher = WidgetMatchModel(kAttr, testValue, static_cast<ValueMatchPattern>(matchPattern));
635 selector->AddMatcher(matcher);
636 out.resultValue_ = StoreBackendObject(move(selector));
637 }
638
RegisterOnBuilders()639 static void RegisterOnBuilders()
640 {
641 auto &server = FrontendApiServer::Get();
642 server.AddHandler("On.accessibilityId", GenericOnAttrBuilder<UiAttr::ACCESSIBILITY_ID, int32_t>);
643 server.AddHandler("On.text", GenericOnAttrBuilder<UiAttr::TEXT, string>);
644 server.AddHandler("On.id", GenericOnAttrBuilder<UiAttr::ID, string>);
645 server.AddHandler("On.description", GenericOnAttrBuilder<UiAttr::DESCRIPTION, string>);
646 server.AddHandler("On.type", GenericOnAttrBuilder<UiAttr::TYPE, string>);
647 server.AddHandler("On.enabled", GenericOnAttrBuilder<UiAttr::ENABLED, bool>);
648 server.AddHandler("On.focused", GenericOnAttrBuilder<UiAttr::FOCUSED, bool>);
649 server.AddHandler("On.selected", GenericOnAttrBuilder<UiAttr::SELECTED, bool>);
650 server.AddHandler("On.clickable", GenericOnAttrBuilder<UiAttr::CLICKABLE, bool>);
651 server.AddHandler("On.longClickable", GenericOnAttrBuilder<UiAttr::LONG_CLICKABLE, bool>);
652 server.AddHandler("On.scrollable", GenericOnAttrBuilder<UiAttr::SCROLLABLE, bool>);
653 server.AddHandler("On.checkable", GenericOnAttrBuilder<UiAttr::CHECKABLE, bool>);
654 server.AddHandler("On.checked", GenericOnAttrBuilder<UiAttr::CHECKED, bool>);
655
656 auto genericRelativeBuilder = [](const ApiCallInfo &in, ApiReplyInfo &out) {
657 const auto attrName = in.apiId_.substr(ON_DEF.name_.length() + 1); // On.xxx()->xxx
658 // always create and return a new selector
659 auto selector = make_unique<WidgetSelector>();
660 if (in.callerObjRef_ != REF_SEED_ON) { // copy-construct from the caller if it's not seed
661 *selector = GetBackendObject<WidgetSelector>(in.callerObjRef_);
662 }
663 if (attrName == "isBefore") {
664 auto &that = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
665 selector->AddRearLocator(that, out.exception_);
666 } else if (attrName == "isAfter") {
667 auto &that = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
668 selector->AddFrontLocator(that, out.exception_);
669 } else if (attrName == "within") {
670 auto &that = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
671 selector->AddParentLocator(that, out.exception_);
672 } else if (attrName == "inWindow") {
673 auto hostApp = ReadCallArg<string>(in, INDEX_ZERO);
674 selector->AddAppLocator(hostApp);
675 }
676 out.resultValue_ = StoreBackendObject(move(selector));
677 };
678 server.AddHandler("On.isBefore", genericRelativeBuilder);
679 server.AddHandler("On.isAfter", genericRelativeBuilder);
680 server.AddHandler("On.within", genericRelativeBuilder);
681 server.AddHandler("On.inWindow", genericRelativeBuilder);
682 }
683
RegisterUiDriverComponentFinders()684 static void RegisterUiDriverComponentFinders()
685 {
686 auto &server = FrontendApiServer::Get();
687 auto genericFindWidgetHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
688 const auto driverRef = in.callerObjRef_;
689 auto &driver = GetBackendObject<UiDriver>(driverRef);
690 auto &selector = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
691 UiOpArgs uiOpArgs;
692 vector<unique_ptr<Widget>> recv;
693 if (in.apiId_ == "Driver.waitForComponent") {
694 uiOpArgs.waitWidgetMaxMs_ = ReadCallArg<int32_t>(in, INDEX_ONE);
695 selector.SetWantMulti(false);
696 auto result = driver.WaitForWidget(selector, uiOpArgs, out.exception_);
697 if (result != nullptr) {
698 recv.emplace_back(move(result));
699 }
700 } else {
701 selector.SetWantMulti(in.apiId_ == "Driver.findComponents");
702 driver.FindWidgets(selector, recv, out.exception_);
703 }
704 if (out.exception_.code_ != NO_ERROR) {
705 LOG_W("genericFindWidgetHandler has error: %{public}s", out.exception_.message_.c_str());
706 return;
707 }
708 if (in.apiId_ == "Driver.assertComponentExist") {
709 if (recv.empty()) { // widget-exist assertion failure, deliver exception
710 out.exception_.code_ = ERR_ASSERTION_FAILED;
711 out.exception_.message_ = "Component not exist matching: " + selector.Describe();
712 }
713 } else if (in.apiId_ == "Driver.findComponents") { // return widget array, maybe empty
714 for (auto &ptr : recv) {
715 out.resultValue_.emplace_back(StoreBackendObject(move(ptr), driverRef));
716 }
717 } else if (recv.empty()) { // return first one or null
718 out.resultValue_ = nullptr;
719 } else {
720 out.resultValue_ = StoreBackendObject(move(*(recv.begin())), driverRef);
721 }
722 };
723 server.AddHandler("Driver.findComponent", genericFindWidgetHandler);
724 server.AddHandler("Driver.findComponents", genericFindWidgetHandler);
725 server.AddHandler("Driver.waitForComponent", genericFindWidgetHandler);
726 server.AddHandler("Driver.assertComponentExist", genericFindWidgetHandler);
727 }
728
RegisterUiDriverWindowFinder()729 static void RegisterUiDriverWindowFinder()
730 {
731 auto findWindowHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
732 const auto driverRef = in.callerObjRef_;
733 auto &driver = GetBackendObject<UiDriver>(driverRef);
734 auto filterJson = ReadCallArg<json>(in, INDEX_ZERO);
735 if (filterJson.empty()) {
736 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "WindowFilter cannot be empty");
737 return;
738 }
739 auto matcher = [&filterJson](const Window &window) -> bool {
740 bool match = true;
741 if (filterJson.contains("bundleName")) {
742 match = match && (filterJson["bundleName"].get<string>() == window.bundleName_);
743 }
744 if (filterJson.contains("title")) {
745 match = match && (filterJson["title"].get<string>() == window.title_);
746 }
747 if (filterJson.contains("focused")) {
748 match = match && (filterJson["focused"].get<bool>() == window.focused_);
749 }
750 if (filterJson.contains("actived")) {
751 match = match && (filterJson["actived"].get<bool>() == window.actived_);
752 }
753 if (filterJson.contains("active")) {
754 match = match && (filterJson["active"].get<bool>() == window.actived_);
755 }
756 return match;
757 };
758 auto window = driver.FindWindow(matcher, out.exception_, filterJson.contains("title"));
759 if (window == nullptr) {
760 LOG_W("There is no match window by %{public}s", filterJson.dump().data());
761 out.resultValue_ = nullptr;
762 } else {
763 out.resultValue_ = StoreBackendObject(move(window), driverRef);
764 }
765 };
766 FrontendApiServer::Get().AddHandler("Driver.findWindow", findWindowHandler);
767 }
768
RegisterUiDriverMiscMethods1()769 static void RegisterUiDriverMiscMethods1()
770 {
771 auto &server = FrontendApiServer::Get();
772 auto create = [](const ApiCallInfo &in, ApiReplyInfo &out) {
773 auto driver = make_unique<UiDriver>();
774 if (driver->CheckStatus(true, out.exception_)) {
775 out.resultValue_ = StoreBackendObject(move(driver));
776 }
777 };
778 server.AddHandler("Driver.create", create);
779
780 auto createUIEventObserver = [](const ApiCallInfo &in, ApiReplyInfo &out) {
781 auto observer = make_unique<UIEventObserver>();
782 out.resultValue_ = StoreBackendObject(move(observer), in.callerObjRef_);
783 };
784 server.AddHandler("Driver.createUIEventObserver", createUIEventObserver);
785
786 auto delay = [](const ApiCallInfo &in, ApiReplyInfo &out) {
787 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
788 auto time = ReadCallArg<int32_t>(in, INDEX_ZERO);
789 driver.DelayMs(time);
790 };
791 server.AddHandler("Driver.delayMs", delay);
792
793 auto screenCap = [](const ApiCallInfo &in, ApiReplyInfo &out) {
794 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
795 auto null = json();
796 auto rectJson = ReadCallArg<json>(in, INDEX_ONE, null);
797 Rect rect = {0, 0, 0, 0};
798 if (!rectJson.empty()) {
799 rect = Rect(rectJson["left"], rectJson["right"], rectJson["top"], rectJson["bottom"]);
800 }
801 auto fd = ReadCallArg<uint32_t>(in, INDEX_ZERO);
802 driver.TakeScreenCap(fd, out.exception_, rect);
803 out.resultValue_ = (out.exception_.code_ == NO_ERROR);
804 (void) close(fd);
805 };
806 server.AddHandler("Driver.screenCap", screenCap);
807 server.AddHandler("Driver.screenCapture", screenCap);
808 }
809
RegisterUiDriverMiscMethods2()810 static void RegisterUiDriverMiscMethods2()
811 {
812 auto &server = FrontendApiServer::Get();
813 auto pressBack = [](const ApiCallInfo &in, ApiReplyInfo &out) {
814 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
815 UiOpArgs uiOpArgs;
816 driver.TriggerKey(Back(), uiOpArgs, out.exception_);
817 };
818 server.AddHandler("Driver.pressBack", pressBack);
819 auto pressHome = [](const ApiCallInfo &in, ApiReplyInfo &out) {
820 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
821 UiOpArgs uiOpArgs;
822 auto keyAction = CombinedKeys(KEYCODE_WIN, KEYCODE_D, KEYCODE_NONE);
823 driver.TriggerKey(keyAction, uiOpArgs, out.exception_);
824 driver.TriggerKey(Home(), uiOpArgs, out.exception_);
825 };
826 server.AddHandler("Driver.pressHome", pressHome);
827 auto triggerKey = [](const ApiCallInfo &in, ApiReplyInfo &out) {
828 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
829 UiOpArgs uiOpArgs;
830 auto key = AnonymousSingleKey(ReadCallArg<int32_t>(in, INDEX_ZERO));
831 driver.TriggerKey(key, uiOpArgs, out.exception_);
832 };
833 server.AddHandler("Driver.triggerKey", triggerKey);
834 auto triggerCombineKeys = [](const ApiCallInfo &in, ApiReplyInfo &out) {
835 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
836 UiOpArgs uiOpArgs;
837 auto key0 = ReadCallArg<int32_t>(in, INDEX_ZERO);
838 auto key1 = ReadCallArg<int32_t>(in, INDEX_ONE);
839 auto key2 = ReadCallArg<int32_t>(in, INDEX_TWO, KEYCODE_NONE);
840 auto keyAction = CombinedKeys(key0, key1, key2);
841 driver.TriggerKey(keyAction, uiOpArgs, out.exception_);
842 };
843 server.AddHandler("Driver.triggerCombineKeys", triggerCombineKeys);
844
845 auto inputText = [](const ApiCallInfo &in, ApiReplyInfo &out) {
846 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
847 UiOpArgs uiOpArgs;
848 auto pointJson = ReadCallArg<json>(in, INDEX_ZERO);
849 auto point = Point(pointJson["x"], pointJson["y"]);
850 auto text = ReadCallArg<string>(in, INDEX_ONE);
851 auto touch = GenericClick(TouchOp::CLICK, point);
852 driver.PerformTouch(touch, uiOpArgs, out.exception_);
853 static constexpr uint32_t focusTimeMs = 500;
854 driver.DelayMs(focusTimeMs);
855 driver.InputText(text, out.exception_);
856 };
857 server.AddHandler("Driver.inputText", inputText);
858 }
859
RegisterUiEventObserverMethods()860 static void RegisterUiEventObserverMethods()
861 {
862 static bool observerDelegateRegistered = false;
863 static auto fowarder = std::make_shared<UiEventFowarder>();
864 auto &server = FrontendApiServer::Get();
865 auto once = [](const ApiCallInfo &in, ApiReplyInfo &out) {
866 auto &driver = GetBoundUiDriver(in.callerObjRef_);
867 auto event = ReadCallArg<string>(in, INDEX_ZERO);
868 auto cbRef = ReadCallArg<string>(in, INDEX_ONE);
869 fowarder->AddCallbackInfo(move(event), in.callerObjRef_, move(cbRef));
870 if (!observerDelegateRegistered) {
871 driver.RegisterUiEventListener(fowarder);
872 observerDelegateRegistered = true;
873 }
874 };
875 server.AddHandler("UIEventObserver.once", once);
876 }
877
CheckSwipeVelocityPps(UiOpArgs& args)878 static void CheckSwipeVelocityPps(UiOpArgs& args)
879 {
880 if (args.swipeVelocityPps_ < args.minSwipeVelocityPps_ || args.swipeVelocityPps_ > args.maxSwipeVelocityPps_) {
881 LOG_W("The swipe velocity out of range");
882 args.swipeVelocityPps_ = args.defaultSwipeVelocityPps_;
883 }
884 }
885
RegisterUiDriverTouchOperators()886 static void RegisterUiDriverTouchOperators()
887 {
888 auto &server = FrontendApiServer::Get();
889 auto genericClick = [](const ApiCallInfo &in, ApiReplyInfo &out) {
890 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
891 const auto point0 = Point(ReadCallArg<int32_t>(in, INDEX_ZERO), ReadCallArg<int32_t>(in, INDEX_ONE));
892 auto point1 = Point(0, 0);
893 UiOpArgs uiOpArgs;
894 auto op = TouchOp::CLICK;
895 if (in.apiId_ == "Driver.longClick") {
896 op = TouchOp::LONG_CLICK;
897 } else if (in.apiId_ == "Driver.doubleClick") {
898 op = TouchOp::DOUBLE_CLICK_P;
899 } else if (in.apiId_ == "Driver.swipe") {
900 op = TouchOp::SWIPE;
901 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_FOUR, uiOpArgs.swipeVelocityPps_);
902 CheckSwipeVelocityPps(uiOpArgs);
903 point1 = Point(ReadCallArg<int32_t>(in, INDEX_TWO), ReadCallArg<int32_t>(in, INDEX_THREE));
904 } else if (in.apiId_ == "Driver.drag") {
905 op = TouchOp::DRAG;
906 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_FOUR, uiOpArgs.swipeVelocityPps_);
907 CheckSwipeVelocityPps(uiOpArgs);
908 point1 = Point(ReadCallArg<int32_t>(in, INDEX_TWO), ReadCallArg<int32_t>(in, INDEX_THREE));
909 }
910 if (op == TouchOp::SWIPE || op == TouchOp::DRAG) {
911 auto touch = GenericSwipe(op, point0, point1);
912 driver.PerformTouch(touch, uiOpArgs, out.exception_);
913 } else {
914 auto touch = GenericClick(op, point0);
915 driver.PerformTouch(touch, uiOpArgs, out.exception_);
916 }
917 };
918 server.AddHandler("Driver.click", genericClick);
919 server.AddHandler("Driver.longClick", genericClick);
920 server.AddHandler("Driver.doubleClick", genericClick);
921 server.AddHandler("Driver.swipe", genericClick);
922 server.AddHandler("Driver.drag", genericClick);
923 }
924
CheckMultiPointerOperatorsPoint(const PointerMatrix& pointer)925 static bool CheckMultiPointerOperatorsPoint(const PointerMatrix& pointer)
926 {
927 for (uint32_t fingerIndex = 0; fingerIndex < pointer.GetFingers(); fingerIndex++) {
928 for (uint32_t stepIndex = 0; stepIndex < pointer.GetSteps(); stepIndex++) {
929 if (pointer.At(fingerIndex, stepIndex).flags_ != 1) {
930 return false;
931 }
932 }
933 }
934 return true;
935 }
936
CreateFlingPoint(Point &to, Point &from, Point screenSize, Direction direction)937 static void CreateFlingPoint(Point &to, Point &from, Point screenSize, Direction direction)
938 {
939 to = Point(screenSize.px_ / INDEX_TWO, screenSize.py_ / INDEX_TWO);
940 switch (direction) {
941 case TO_LEFT:
942 from.px_ = to.px_ - screenSize.px_ / INDEX_FOUR;
943 from.py_ = to.py_;
944 break;
945 case TO_RIGHT:
946 from.px_ = to.px_ + screenSize.px_ / INDEX_FOUR;
947 from.py_ = to.py_;
948 break;
949 case TO_UP:
950 from.px_ = to.px_;
951 from.py_ = to.py_ - screenSize.py_ / INDEX_FOUR;
952 break;
953 case TO_DOWN:
954 from.px_ = to.px_;
955 from.py_ = to.py_ + screenSize.py_ / INDEX_FOUR;
956 break;
957 default:
958 break;
959 }
960 }
961
RegisterUiDriverFlingOperators()962 static void RegisterUiDriverFlingOperators()
963 {
964 auto &server = FrontendApiServer::Get();
965 auto genericFling = [](const ApiCallInfo &in, ApiReplyInfo &out) {
966 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
967 UiOpArgs uiOpArgs;
968 auto op = TouchOp::FLING;
969 auto params = in.paramList_;
970 Point from;
971 Point to;
972 if (params.size() == INDEX_TWO) {
973 auto screenSize = driver.GetDisplaySize(out.exception_);
974 auto direction = ReadCallArg<Direction>(in, INDEX_ZERO);
975 CreateFlingPoint(to, from, screenSize, direction);
976 uiOpArgs.swipeStepsCounts_ = INDEX_TWO;
977 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_ONE);
978 } else {
979 auto pointJson0 = ReadCallArg<json>(in, INDEX_ZERO);
980 auto pointJson1 = ReadCallArg<json>(in, INDEX_ONE);
981 if (pointJson0.empty() || pointJson1.empty()) {
982 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Point cannot be empty");
983 return;
984 }
985 from = Point(pointJson0["x"], pointJson0["y"]);
986 to = Point(pointJson1["x"], pointJson1["y"]);
987 auto stepLength = ReadCallArg<uint32_t>(in, INDEX_TWO);
988 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_THREE);
989 const int32_t distanceX = to.px_ - from.px_;
990 const int32_t distanceY = to.py_ - from.py_;
991 const uint32_t distance = sqrt(distanceX * distanceX + distanceY * distanceY);
992 if (stepLength <= 0 || stepLength > distance) {
993 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "The stepLen is out of range");
994 return;
995 }
996 uiOpArgs.swipeStepsCounts_ = distance / stepLength;
997 }
998 CheckSwipeVelocityPps(uiOpArgs);
999 auto touch = GenericSwipe(op, from, to);
1000 driver.PerformTouch(touch, uiOpArgs, out.exception_);
1001 };
1002 server.AddHandler("Driver.fling", genericFling);
1003 }
1004
RegisterUiDriverMultiPointerOperators()1005 static void RegisterUiDriverMultiPointerOperators()
1006 {
1007 auto &server = FrontendApiServer::Get();
1008 auto multiPointerAction = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1009 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
1010 auto &pointer = GetBackendObject<PointerMatrix>(ReadCallArg<string>(in, INDEX_ZERO));
1011 auto flag = CheckMultiPointerOperatorsPoint(pointer);
1012 if (!flag) {
1013 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "There is not all coordinate points are set");
1014 return;
1015 }
1016 UiOpArgs uiOpArgs;
1017 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_ONE, uiOpArgs.swipeVelocityPps_);
1018 CheckSwipeVelocityPps(uiOpArgs);
1019 auto touch = MultiPointerAction(pointer);
1020 driver.PerformTouch(touch, uiOpArgs, out.exception_);
1021 out.resultValue_ = (out.exception_.code_ == NO_ERROR);
1022 };
1023 server.AddHandler("Driver.injectMultiPointerAction", multiPointerAction);
1024 }
1025
RegisterUiDriverMouseOperators1()1026 static void RegisterUiDriverMouseOperators1()
1027 {
1028 auto &server = FrontendApiServer::Get();
1029 auto mouseClick = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1030 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
1031 UiOpArgs uiOpArgs;
1032 auto pointJson = ReadCallArg<json>(in, INDEX_ZERO);
1033 auto point = Point(pointJson["x"], pointJson["y"]);
1034 auto button = ReadCallArg<MouseButton>(in, INDEX_ONE);
1035 auto key1 = ReadCallArg<int32_t>(in, INDEX_TWO, KEYCODE_NONE);
1036 auto key2 = ReadCallArg<int32_t>(in, INDEX_THREE, KEYCODE_NONE);
1037 auto op = TouchOp::CLICK;
1038 if (in.apiId_ == "Driver.mouseDoubleClick") {
1039 op = TouchOp::DOUBLE_CLICK_P;
1040 } else if (in.apiId_ == "Driver.mouseLongClick") {
1041 op = TouchOp::LONG_CLICK;
1042 }
1043 auto touch = MouseClick(op, point, button, key1, key2);
1044 driver.PerformMouseAction(touch, uiOpArgs, out.exception_);
1045 };
1046 server.AddHandler("Driver.mouseClick", mouseClick);
1047 server.AddHandler("Driver.mouseDoubleClick", mouseClick);
1048 server.AddHandler("Driver.mouseLongClick", mouseClick);
1049 }
1050
RegisterUiDriverMouseOperators2()1051 static void RegisterUiDriverMouseOperators2()
1052 {
1053 auto &server = FrontendApiServer::Get();
1054 auto mouseMoveTo = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1055 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
1056 UiOpArgs uiOpArgs;
1057 auto pointJson = ReadCallArg<json>(in, INDEX_ZERO);
1058 auto point = Point(pointJson["x"], pointJson["y"]);
1059 auto touch = MouseMoveTo(point);
1060 driver.PerformMouseAction(touch, uiOpArgs, out.exception_);
1061 };
1062 server.AddHandler("Driver.mouseMoveTo", mouseMoveTo);
1063
1064 auto mouseSwipe = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1065 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
1066 auto pointJson1 = ReadCallArg<json>(in, INDEX_ZERO);
1067 auto pointJson2 = ReadCallArg<json>(in, INDEX_ONE);
1068 auto from = Point(pointJson1["x"], pointJson1["y"]);
1069 auto to = Point(pointJson2["x"], pointJson2["y"]);
1070 UiOpArgs uiOpArgs;
1071 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_TWO, uiOpArgs.swipeVelocityPps_);
1072 CheckSwipeVelocityPps(uiOpArgs);
1073 auto op = TouchOp::SWIPE;
1074 if (in.apiId_ == "Driver.mouseDrag") {
1075 op = TouchOp::DRAG;
1076 }
1077 auto touch = MouseSwipe(op, from, to);
1078 driver.PerformMouseAction(touch, uiOpArgs, out.exception_);
1079 };
1080 server.AddHandler("Driver.mouseMoveWithTrack", mouseSwipe);
1081 server.AddHandler("Driver.mouseDrag", mouseSwipe);
1082
1083 auto mouseScroll = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1084 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
1085 UiOpArgs uiOpArgs;
1086 auto pointJson = ReadCallArg<json>(in, INDEX_ZERO);
1087 auto point = Point(pointJson["x"], pointJson["y"]);
1088 auto scrollValue = ReadCallArg<int32_t>(in, INDEX_TWO);
1089 auto adown = ReadCallArg<bool>(in, INDEX_ONE);
1090 scrollValue = adown ? scrollValue : -scrollValue;
1091 auto key1 = ReadCallArg<int32_t>(in, INDEX_THREE, KEYCODE_NONE);
1092 auto key2 = ReadCallArg<int32_t>(in, INDEX_FOUR, KEYCODE_NONE);
1093 const uint32_t maxScrollSpeed = 500;
1094 const uint32_t defaultScrollSpeed = 20;
1095 auto speed = ReadCallArg<uint32_t>(in, INDEX_FIVE, defaultScrollSpeed);
1096 if (speed < 1 || speed > maxScrollSpeed) {
1097 speed = defaultScrollSpeed;
1098 }
1099 auto touch = MouseScroll(point, scrollValue, key1, key2, speed);
1100 driver.PerformMouseAction(touch, uiOpArgs, out.exception_);
1101 };
1102 server.AddHandler("Driver.mouseScroll", mouseScroll);
1103 }
1104
RegisterUiDriverDisplayOperators()1105 static void RegisterUiDriverDisplayOperators()
1106 {
1107 auto &server = FrontendApiServer::Get();
1108 auto genericDisplayOperator = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1109 auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
1110 if (in.apiId_ == "Driver.setDisplayRotation") {
1111 auto rotation = ReadCallArg<DisplayRotation>(in, INDEX_ZERO);
1112 driver.SetDisplayRotation(rotation, out.exception_);
1113 } else if (in.apiId_ == "Driver.getDisplayRotation") {
1114 out.resultValue_ = driver.GetDisplayRotation(out.exception_);
1115 } else if (in.apiId_ == "Driver.setDisplayRotationEnabled") {
1116 auto enabled = ReadCallArg<bool>(in, INDEX_ZERO);
1117 driver.SetDisplayRotationEnabled(enabled, out.exception_);
1118 } else if (in.apiId_ == "Driver.waitForIdle") {
1119 auto idleTime = ReadCallArg<int32_t>(in, INDEX_ZERO);
1120 auto timeout = ReadCallArg<int32_t>(in, INDEX_ONE);
1121 out.resultValue_ = driver.WaitForUiSteady(idleTime, timeout, out.exception_);
1122 } else if (in.apiId_ == "Driver.wakeUpDisplay") {
1123 driver.WakeUpDisplay(out.exception_);
1124 } else if (in.apiId_ == "Driver.getDisplaySize") {
1125 auto result = driver.GetDisplaySize(out.exception_);
1126 json data;
1127 data["x"] = result.px_;
1128 data["y"] = result.py_;
1129 out.resultValue_ = data;
1130 } else if (in.apiId_ == "Driver.getDisplayDensity") {
1131 auto result = driver.GetDisplayDensity(out.exception_);
1132 json data;
1133 data["x"] = result.px_;
1134 data["y"] = result.py_;
1135 out.resultValue_ = data;
1136 }
1137 };
1138 server.AddHandler("Driver.setDisplayRotation", genericDisplayOperator);
1139 server.AddHandler("Driver.getDisplayRotation", genericDisplayOperator);
1140 server.AddHandler("Driver.setDisplayRotationEnabled", genericDisplayOperator);
1141 server.AddHandler("Driver.waitForIdle", genericDisplayOperator);
1142 server.AddHandler("Driver.wakeUpDisplay", genericDisplayOperator);
1143 server.AddHandler("Driver.getDisplaySize", genericDisplayOperator);
1144 server.AddHandler("Driver.getDisplayDensity", genericDisplayOperator);
1145 }
1146
1147 template <UiAttr kAttr, bool kString = false>
GenericComponentAttrGetter(const ApiCallInfo &in, ApiReplyInfo &out)1148 static void GenericComponentAttrGetter(const ApiCallInfo &in, ApiReplyInfo &out)
1149 {
1150 constexpr auto attrName = ATTR_NAMES[kAttr];
1151 auto &image = GetBackendObject<Widget>(in.callerObjRef_);
1152 auto &driver = GetBoundUiDriver(in.callerObjRef_);
1153 auto snapshot = driver.RetrieveWidget(image, out.exception_);
1154 if (out.exception_.code_ != NO_ERROR) {
1155 out.resultValue_ = nullptr; // exception, return null
1156 return;
1157 }
1158 if (attrName == ATTR_NAMES[UiAttr::BOUNDSCENTER]) { // getBoundsCenter
1159 const auto bounds = snapshot->GetBounds();
1160 json data;
1161 data["x"] = bounds.GetCenterX();
1162 data["y"] = bounds.GetCenterY();
1163 out.resultValue_ = data;
1164 return;
1165 }
1166 if (attrName == ATTR_NAMES[UiAttr::BOUNDS]) { // getBounds
1167 const auto bounds = snapshot->GetBounds();
1168 json data;
1169 data["left"] = bounds.left_;
1170 data["top"] = bounds.top_;
1171 data["right"] = bounds.right_;
1172 data["bottom"] = bounds.bottom_;
1173 out.resultValue_ = data;
1174 return;
1175 }
1176 // convert value-string to json value of target type
1177 auto attrValue = snapshot->GetAttr(kAttr);
1178 if (attrValue == "NA") {
1179 out.resultValue_ = nullptr; // no such attribute, return null
1180 } else if (kString) {
1181 out.resultValue_ = attrValue;
1182 } else {
1183 out.resultValue_ = nlohmann::json::parse(attrValue);
1184 }
1185 }
1186
RegisterExtensionHandler()1187 static void RegisterExtensionHandler()
1188 {
1189 auto &server = FrontendApiServer::Get();
1190 auto genericOperationHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1191 auto &image = GetBackendObject<Widget>(in.callerObjRef_);
1192 auto &driver = GetBoundUiDriver(in.callerObjRef_);
1193 auto snapshot = driver.RetrieveWidget(image, out.exception_);
1194 if (out.exception_.code_ != NO_ERROR || snapshot == nullptr) {
1195 out.resultValue_ = nullptr; // exception, return null
1196 return;
1197 }
1198 json data;
1199 for (auto i = 0; i < UiAttr::HIERARCHY + 1; ++i) {
1200 if (i == UiAttr::BOUNDS) {
1201 const auto bounds = snapshot->GetBounds();
1202 json rect;
1203 rect["left"] = bounds.left_;
1204 rect["top"] = bounds.top_;
1205 rect["right"] = bounds.right_;
1206 rect["bottom"] = bounds.bottom_;
1207 data["bounds"] = rect;
1208 continue;
1209 }
1210 data[ATTR_NAMES[i].data()] = snapshot->GetAttr(static_cast<UiAttr> (i));
1211 }
1212 out.resultValue_ = data;
1213 };
1214 server.AddHandler("Component.getAllProperties", genericOperationHandler);
1215 }
1216
RegisterUiComponentAttrGetters()1217 static void RegisterUiComponentAttrGetters()
1218 {
1219 auto &server = FrontendApiServer::Get();
1220 server.AddHandler("Component.getAccessibilityId", GenericComponentAttrGetter<UiAttr::ACCESSIBILITY_ID>);
1221 server.AddHandler("Component.getText", GenericComponentAttrGetter<UiAttr::TEXT, true>);
1222 server.AddHandler("Component.getDescription", GenericComponentAttrGetter<UiAttr::DESCRIPTION, true>);
1223 server.AddHandler("Component.getId", GenericComponentAttrGetter<UiAttr::ID, true>);
1224 server.AddHandler("Component.getType", GenericComponentAttrGetter<UiAttr::TYPE, true>);
1225 server.AddHandler("Component.isEnabled", GenericComponentAttrGetter<UiAttr::ENABLED>);
1226 server.AddHandler("Component.isFocused", GenericComponentAttrGetter<UiAttr::FOCUSED>);
1227 server.AddHandler("Component.isSelected", GenericComponentAttrGetter<UiAttr::SELECTED>);
1228 server.AddHandler("Component.isClickable", GenericComponentAttrGetter<UiAttr::CLICKABLE>);
1229 server.AddHandler("Component.isLongClickable", GenericComponentAttrGetter<UiAttr::LONG_CLICKABLE>);
1230 server.AddHandler("Component.isScrollable", GenericComponentAttrGetter<UiAttr::SCROLLABLE>);
1231 server.AddHandler("Component.isCheckable", GenericComponentAttrGetter<UiAttr::CHECKABLE>);
1232 server.AddHandler("Component.isChecked", GenericComponentAttrGetter<UiAttr::CHECKED>);
1233 server.AddHandler("Component.getBounds", GenericComponentAttrGetter<UiAttr::BOUNDS>);
1234 server.AddHandler("Component.getBoundsCenter", GenericComponentAttrGetter<UiAttr::BOUNDSCENTER>);
1235 }
1236
RegisterUiComponentOperators1()1237 static void RegisterUiComponentOperators1()
1238 {
1239 auto &server = FrontendApiServer::Get();
1240 auto genericOperationHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1241 auto &widget = GetBackendObject<Widget>(in.callerObjRef_);
1242 auto &driver = GetBoundUiDriver(in.callerObjRef_);
1243 UiOpArgs uiOpArgs;
1244 auto wOp = WidgetOperator(driver, widget, uiOpArgs);
1245 if (in.apiId_ == "Component.click") {
1246 wOp.GenericClick(TouchOp::CLICK, out.exception_);
1247 } else if (in.apiId_ == "Component.longClick") {
1248 wOp.GenericClick(TouchOp::LONG_CLICK, out.exception_);
1249 } else if (in.apiId_ == "Component.doubleClick") {
1250 wOp.GenericClick(TouchOp::DOUBLE_CLICK_P, out.exception_);
1251 } else if (in.apiId_ == "Component.scrollToTop") {
1252 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_ZERO, uiOpArgs.swipeVelocityPps_);
1253 CheckSwipeVelocityPps(uiOpArgs);
1254 wOp.ScrollToEnd(true, out.exception_);
1255 } else if (in.apiId_ == "Component.scrollToBottom") {
1256 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_ZERO, uiOpArgs.swipeVelocityPps_);
1257 CheckSwipeVelocityPps(uiOpArgs);
1258 wOp.ScrollToEnd(false, out.exception_);
1259 } else if (in.apiId_ == "Component.dragTo") {
1260 auto &widgetTo = GetBackendObject<Widget>(ReadCallArg<string>(in, INDEX_ZERO));
1261 wOp.DragIntoWidget(widgetTo, out.exception_);
1262 } else if (in.apiId_ == "Component.inputText") {
1263 wOp.InputText(ReadCallArg<string>(in, INDEX_ZERO), out.exception_);
1264 } else if (in.apiId_ == "Component.clearText") {
1265 wOp.InputText("", out.exception_);
1266 } else if (in.apiId_ == "Component.scrollSearch") {
1267 auto &selector = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
1268 auto res = wOp.ScrollFindWidget(selector, out.exception_);
1269 if (res != nullptr) {
1270 out.resultValue_ = StoreBackendObject(move(res), sDriverBindingMap.find(in.callerObjRef_)->second);
1271 }
1272 }
1273 };
1274 server.AddHandler("Component.click", genericOperationHandler);
1275 server.AddHandler("Component.longClick", genericOperationHandler);
1276 server.AddHandler("Component.doubleClick", genericOperationHandler);
1277 server.AddHandler("Component.scrollToTop", genericOperationHandler);
1278 server.AddHandler("Component.scrollToBottom", genericOperationHandler);
1279 server.AddHandler("Component.dragTo", genericOperationHandler);
1280 server.AddHandler("Component.inputText", genericOperationHandler);
1281 server.AddHandler("Component.clearText", genericOperationHandler);
1282 server.AddHandler("Component.scrollSearch", genericOperationHandler);
1283 }
1284
RegisterUiComponentOperators2()1285 static void RegisterUiComponentOperators2()
1286 {
1287 auto &server = FrontendApiServer::Get();
1288 auto genericOperationHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1289 auto &widget = GetBackendObject<Widget>(in.callerObjRef_);
1290 auto &driver = GetBoundUiDriver(in.callerObjRef_);
1291 UiOpArgs uiOpArgs;
1292 auto wOp = WidgetOperator(driver, widget, uiOpArgs);
1293 if (in.apiId_ == "Component.pinchOut") {
1294 auto pinchScale = ReadCallArg<float_t>(in, INDEX_ZERO);
1295 if (pinchScale < 1) {
1296 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Expect integer which gerater 1");
1297 }
1298 wOp.PinchWidget(pinchScale, out.exception_);
1299 } else if (in.apiId_ == "Component.pinchIn") {
1300 auto pinchScale = ReadCallArg<float_t>(in, INDEX_ZERO);
1301 if (pinchScale > 1) {
1302 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Expect integer which ranges from 0 to 1.");
1303 }
1304 wOp.PinchWidget(pinchScale, out.exception_);
1305 }
1306 };
1307 server.AddHandler("Component.pinchOut", genericOperationHandler);
1308 server.AddHandler("Component.pinchIn", genericOperationHandler);
1309 }
1310
RegisterUiWindowAttrGetters()1311 static void RegisterUiWindowAttrGetters()
1312 {
1313 auto &server = FrontendApiServer::Get();
1314 auto genericGetter = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1315 auto &window = GetBackendObject<Window>(in.callerObjRef_);
1316 auto &driver = GetBoundUiDriver(in.callerObjRef_);
1317 auto snapshot = driver.RetrieveWindow(window, out.exception_, in.apiId_ == "UiWindow.getTitle");
1318 if (out.exception_.code_ != NO_ERROR) {
1319 out.resultValue_ = nullptr; // exception, return null
1320 return;
1321 }
1322 if (in.apiId_ == "UiWindow.getBundleName") {
1323 out.resultValue_ = snapshot->bundleName_;
1324 } else if (in.apiId_ == "UiWindow.getBounds") {
1325 json data;
1326 data["left"] = snapshot->bounds_.left_;
1327 data["top"] = snapshot->bounds_.top_;
1328 data["right"] = snapshot->bounds_.right_;
1329 data["bottom"] = snapshot->bounds_.bottom_;
1330 out.resultValue_ = data;
1331 } else if (in.apiId_ == "UiWindow.getTitle") {
1332 out.resultValue_ = snapshot->title_;
1333 } else if (in.apiId_ == "UiWindow.getWindowMode") {
1334 out.resultValue_ = (uint8_t)(snapshot->mode_ - 1);
1335 } else if (in.apiId_ == "UiWindow.isFocused") {
1336 out.resultValue_ = snapshot->focused_;
1337 } else if (in.apiId_ == "UiWindow.isActive") {
1338 out.resultValue_ = snapshot->actived_;
1339 }
1340 };
1341 server.AddHandler("UiWindow.getBundleName", genericGetter);
1342 server.AddHandler("UiWindow.getBounds", genericGetter);
1343 server.AddHandler("UiWindow.getTitle", genericGetter);
1344 server.AddHandler("UiWindow.getWindowMode", genericGetter);
1345 server.AddHandler("UiWindow.isFocused", genericGetter);
1346 server.AddHandler("UiWindow.isActive", genericGetter);
1347 }
1348
RegisterUiWindowOperators()1349 static void RegisterUiWindowOperators()
1350 {
1351 auto &server = FrontendApiServer::Get();
1352 auto genericWinOperationHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1353 auto &window = GetBackendObject<Window>(in.callerObjRef_);
1354 auto &driver = GetBoundUiDriver(in.callerObjRef_);
1355 UiOpArgs uiOpArgs;
1356 auto wOp = WindowOperator(driver, window, uiOpArgs);
1357 auto action = in.apiId_;
1358 if (action == "UiWindow.resize") {
1359 auto width = ReadCallArg<int32_t>(in, INDEX_ZERO);
1360 auto highth = ReadCallArg<int32_t>(in, INDEX_ONE);
1361 auto direction = ReadCallArg<ResizeDirection>(in, INDEX_TWO);
1362 if ((((direction == LEFT) || (direction == RIGHT)) && highth != window.bounds_.GetHeight()) ||
1363 (((direction == D_UP) || (direction == D_DOWN)) && width != window.bounds_.GetWidth())) {
1364 out.exception_ = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "Resize cannot be done in this direction");
1365 return;
1366 }
1367 wOp.Resize(width, highth, direction, out);
1368 } else if (action == "UiWindow.focus") {
1369 wOp.Focus(out);
1370 }
1371 };
1372 server.AddHandler("UiWindow.focus", genericWinOperationHandler);
1373 server.AddHandler("UiWindow.resize", genericWinOperationHandler);
1374 }
1375
RegisterUiWinBarOperators()1376 static void RegisterUiWinBarOperators()
1377 {
1378 auto &server = FrontendApiServer::Get();
1379 auto genericWinBarOperationHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1380 auto &window = GetBackendObject<Window>(in.callerObjRef_);
1381 auto &driver = GetBoundUiDriver(in.callerObjRef_);
1382 UiOpArgs uiOpArgs;
1383 auto wOp = WindowOperator(driver, window, uiOpArgs);
1384 auto action = in.apiId_;
1385 if (window.decoratorEnabled_) {
1386 if (action == "UiWindow.split") {
1387 wOp.Split(out);
1388 } else if (action == "UiWindow.maximize") {
1389 wOp.Maximize(out);
1390 } else if (action == "UiWindow.resume") {
1391 wOp.Resume(out);
1392 } else if (action == "UiWindow.minimize") {
1393 wOp.Minimize(out);
1394 } else if (action == "UiWindow.close") {
1395 wOp.Close(out);
1396 } else if (action == "UiWindow.moveTo") {
1397 auto endX = ReadCallArg<uint32_t>(in, INDEX_ZERO);
1398 auto endY = ReadCallArg<uint32_t>(in, INDEX_ONE);
1399 wOp.MoveTo(endX, endY, out);
1400 }
1401 } else {
1402 out.exception_ = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "this device can not support this action");
1403 }
1404 };
1405 server.AddHandler("UiWindow.split", genericWinBarOperationHandler);
1406 server.AddHandler("UiWindow.maximize", genericWinBarOperationHandler);
1407 server.AddHandler("UiWindow.resume", genericWinBarOperationHandler);
1408 server.AddHandler("UiWindow.minimize", genericWinBarOperationHandler);
1409 server.AddHandler("UiWindow.close", genericWinBarOperationHandler);
1410 server.AddHandler("UiWindow.moveTo", genericWinBarOperationHandler);
1411 }
1412
RegisterPointerMatrixOperators()1413 static void RegisterPointerMatrixOperators()
1414 {
1415 auto &server = FrontendApiServer::Get();
1416 auto create = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1417 UiOpArgs uiOpArgs;
1418 auto finger = ReadCallArg<uint32_t>(in, INDEX_ZERO);
1419 if (finger < 1 || finger > uiOpArgs.maxMultiTouchFingers) {
1420 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Number of illegal fingers");
1421 return;
1422 }
1423 auto step = ReadCallArg<uint32_t>(in, INDEX_ONE);
1424 if (step < 1 || step > uiOpArgs.maxMultiTouchSteps) {
1425 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Number of illegal steps");
1426 return;
1427 }
1428 out.resultValue_ = StoreBackendObject(make_unique<PointerMatrix>(finger, step));
1429 };
1430 server.AddHandler("PointerMatrix.create", create);
1431
1432 auto setPoint = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1433 auto &pointer = GetBackendObject<PointerMatrix>(in.callerObjRef_);
1434 auto finger = ReadCallArg<uint32_t>(in, INDEX_ZERO);
1435 if (finger < 0 || finger >= pointer.GetFingers()) {
1436 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Number of illegal fingers");
1437 return;
1438 }
1439 auto step = ReadCallArg<uint32_t>(in, INDEX_ONE);
1440 if (step < 0 || step >= pointer.GetSteps()) {
1441 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Number of illegal steps");
1442 return;
1443 }
1444 auto pointJson = ReadCallArg<json>(in, INDEX_TWO);
1445 if (pointJson.empty()) {
1446 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Point cannot be empty");
1447 return;
1448 }
1449 const auto point = Point(pointJson["x"], pointJson["y"]);
1450 pointer.At(finger, step).point_ = point;
1451 pointer.At(finger, step).flags_ = 1;
1452 };
1453 server.AddHandler("PointerMatrix.setPoint", setPoint);
1454 }
1455
1456 /** Register frontendApiHandlers and preprocessors on startup.*/
RegisterApiHandlers()1457 __attribute__((constructor)) static void RegisterApiHandlers()
1458 {
1459 auto &server = FrontendApiServer::Get();
1460 server.AddCommonPreprocessor("APiCallInfoChecker", APiCallInfoChecker);
1461 server.AddHandler("BackendObjectsCleaner", BackendObjectsCleaner);
1462 RegisterOnBuilders();
1463 RegisterUiDriverComponentFinders();
1464 RegisterUiDriverWindowFinder();
1465 RegisterUiDriverMiscMethods1();
1466 RegisterUiDriverMiscMethods2();
1467 RegisterUiDriverTouchOperators();
1468 RegisterUiComponentAttrGetters();
1469 RegisterUiComponentOperators1();
1470 RegisterUiComponentOperators2();
1471 RegisterUiWindowAttrGetters();
1472 RegisterUiWindowOperators();
1473 RegisterUiWinBarOperators();
1474 RegisterPointerMatrixOperators();
1475 RegisterUiDriverFlingOperators();
1476 RegisterUiDriverMultiPointerOperators();
1477 RegisterUiDriverDisplayOperators();
1478 RegisterUiDriverMouseOperators1();
1479 RegisterUiDriverMouseOperators2();
1480 RegisterUiEventObserverMethods();
1481 RegisterExtensionHandler();
1482 }
1483 } // namespace OHOS::uitest
1484