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