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