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