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