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