• 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 "ui_driver.h"
18 #include "widget_operator.h"
19 #include "window_operator.h"
20 #include "frontend_api_handler.h"
21 
22 namespace OHOS::uitest {
23     using namespace std;
24     using namespace nlohmann;
25     using namespace nlohmann::detail;
26 
27     /** API argument type list map.*/
28     static map<string, pair<vector<string>, bool>> sApiArgTypesMap;
29 
ParseMethodSignature(string_view signature,vector<string> & types,bool & defArg)30     static void ParseMethodSignature(string_view signature, vector<string> &types, bool &defArg)
31     {
32         int charIndex = 0;
33         constexpr size_t BUF_LEN = 32;
34         char buf[BUF_LEN];
35         size_t tokenLen = 0;
36         size_t defArgCount = 0;
37         string token;
38         for (char ch : signature) {
39             if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
40                 buf[tokenLen++] = ch;
41             } else if (ch == '?') {
42                 defArgCount++;
43                 DCHECK(defArgCount == 1); // only one defaultArg allowed
44             } else if (ch == ',' || ch == '?' || ch == ')') {
45                 if (tokenLen > 0) {
46                     token = string_view(buf, tokenLen);
47                     DCHECK(find(DATA_TYPE_SCOPE.begin(), DATA_TYPE_SCOPE.end(), token) != DATA_TYPE_SCOPE.end());
48                     types.emplace_back(token);
49                 }
50                 tokenLen = 0; // consume token and reset buffer
51                 if (ch == ')') {
52                     // add return value type to the end of types.
53                     string retType = string(signature.substr(charIndex + 2));
54                     types.emplace_back(retType);
55                     break; // end parsing
56                 }
57             }
58             charIndex++;
59         }
60         defArg = defArgCount > 0;
61     }
62 
63     /** Parse frontend method definitions to collect type information.*/
ParseFrontendMethodsSignature()64     static void ParseFrontendMethodsSignature()
65     {
66         for (auto classDef : FRONTEND_CLASS_DEFS) {
67             LOG_D("parse class %{public}s", string(classDef->name_).c_str());
68             if (classDef->methods_ == nullptr || classDef->methodCount_ <= 0) {
69                 continue;
70             }
71             for (size_t idx = 0; idx < classDef->methodCount_; idx++) {
72                 auto methodDef = classDef->methods_[idx];
73                 auto paramTypes = vector<string>();
74                 auto hasDefaultArg = false;
75                 ParseMethodSignature(methodDef.signature_, paramTypes, hasDefaultArg);
76                 sApiArgTypesMap.insert(make_pair(string(methodDef.name_), make_pair(paramTypes, hasDefaultArg)));
77             }
78         }
79     }
80 
GetClassName(const string & apiName,char splitter)81     static string GetClassName(const string &apiName, char splitter)
82     {
83         auto classNameLen = apiName.find(splitter);
84         if (classNameLen == std::string::npos) {
85             return "";
86         }
87         return apiName.substr(0, classNameLen);
88     }
89 
CheckAndDoApiMapping(string_view apiName,char splitter,const map<string,string> & apiMap)90     static string CheckAndDoApiMapping(string_view apiName, char splitter, const map<string, string> &apiMap)
91     {
92         string output = string(apiName);
93         auto classNameLen = output.find(splitter);
94         if (classNameLen == std::string::npos) {
95             return output;
96         }
97         string className = output.substr(0, classNameLen);
98         auto result = apiMap.find(className);
99         if (result == apiMap.end()) {
100             return output;
101         }
102         auto specialMapItem = apiMap.find(output);
103         if (specialMapItem != apiMap.end()) {
104             output = specialMapItem->second;
105         } else {
106             output.replace(0, classNameLen, result->second);
107         }
108         LOG_D("original className: %{public}s, modified to: %{public}s", className.c_str(), output.c_str());
109         return output;
110     }
111 
FrontendApiServer()112     FrontendApiServer::FrontendApiServer()
113     {
114         old2NewApiMap_["By"] = "On";
115         old2NewApiMap_["UiDriver"] = "Driver";
116         old2NewApiMap_["UiComponent"] = "Component";
117         old2NewApiMap_["By.id"] = "On.accessibilityId";
118         old2NewApiMap_["By.key"] = "On.id";
119         old2NewApiMap_["UiComponent.getId"] = "Component.getAccessibilityId";
120         old2NewApiMap_["UiComponent.getKey"] = "Component.getId";
121         new2OldApiMap_["On"] = "By" ;
122         new2OldApiMap_["Driver"] = "UiDriver" ;
123         new2OldApiMap_["Component"] = "UiComponent" ;
124     }
125 
126     /**
127      * map api8 old api call to new api.
128      * return old api name if it's an old api call.
129      * return empty string if it's a new api call.
130      */
131     static const std::map<ErrCode, std::vector<ErrCode>> ErrCodeMap = {
132         /**Correspondence between old and new error codes*/
133         {NO_ERROR, {NO_ERROR}},
134         {ERR_COMPONENT_LOST, {WIDGET_LOST, WINDOW_LOST}},
135         {ERR_NO_SYSTEM_CAPABILITY, {USAGE_ERROR}},
136         {ERR_INTERNAL, {INTERNAL_ERROR}},
137         {ERR_INITIALIZE_FAILED, {USAGE_ERROR}},
138         {ERR_INVALID_INPUT, {USAGE_ERROR}},
139         {ERR_ASSERTION_FAILED, {ASSERTION_FAILURE}},
140         {ERR_OPERATION_UNSUPPORTED, {INTERNAL_ERROR}},
141         {ERR_API_USAGE, {INTERNAL_ERROR}},
142     };
143 
ApiMapPre(ApiCallInfo & inModifier) const144     string FrontendApiServer::ApiMapPre(ApiCallInfo &inModifier) const
145     {
146         // 1. map method name
147         const string &className = GetClassName(inModifier.apiId_, '.');
148         const auto result = old2NewApiMap_.find(className);
149         if (result == old2NewApiMap_.end()) {
150             return "";
151         }
152         string oldApiName = inModifier.apiId_;
153         inModifier.apiId_ = CheckAndDoApiMapping(inModifier.apiId_, '.', old2NewApiMap_);
154         LOG_D("Modify call name to %{public}s", inModifier.apiId_.c_str());
155         // 2. map callerObjRef
156         if (inModifier.callerObjRef_.find(className) == 0) {
157             inModifier.callerObjRef_.replace(0, className.length(), result->second);
158             LOG_D("Modify callobjref to %{public}s", inModifier.callerObjRef_.c_str());
159         }
160         // 3. map parameters
161         // find method signature of old api
162         const auto find = sApiArgTypesMap.find(oldApiName);
163         if (find == sApiArgTypesMap.end()) {
164             return oldApiName;
165         }
166         const auto &argTypes = find->second.first;
167         size_t argCount = inModifier.paramList_.size();
168         if (argTypes.size() - 1 < argCount) {
169             // parameter number invalid
170             return oldApiName;
171         }
172         for (size_t i = 0; i < argCount; i++) {
173             auto &argItem = inModifier.paramList_.at(i);
174             const string &argType = argTypes.at(i);
175             if (argType != "string" && argItem.type() == value_t::string) {
176                 argItem = CheckAndDoApiMapping(argItem.get<string>(), '#', old2NewApiMap_);
177             }
178         }
179         return oldApiName;
180     }
181 
ErrCodeMapping(ApiCallErr & apiErr)182     static void ErrCodeMapping(ApiCallErr &apiErr)
183     {
184         ErrCode ec = apiErr.code_;
185         auto msg = apiErr.message_;
186         auto findCode = ErrCodeMap.find(ec);
187         if (findCode != ErrCodeMap.end() && !findCode->second.empty()) {
188             apiErr = ApiCallErr(findCode->second.at(0), msg);
189         }
190     }
191 
192     /** map new error code and api Object to old error code and api Object. */
ApiMapPost(const string & oldApiName,ApiReplyInfo & out) const193     void FrontendApiServer::ApiMapPost(const string &oldApiName, ApiReplyInfo &out) const
194     {
195         json &value = out.resultValue_;
196         const auto type = value.type();
197         // 1. error code conversion
198         ErrCodeMapping(out.exception_);
199         // 2. ret value conversion
200         const auto find = sApiArgTypesMap.find(oldApiName);
201         if (find == sApiArgTypesMap.end()) {
202             return;
203         }
204         string &retType = find->second.first.back();
205         if ((retType == "string") || (retType == "[string]")) {
206             return;
207         }
208         if (type == value_t::string) {
209             value = CheckAndDoApiMapping(value.get<string>(), '#', new2OldApiMap_);
210         } else if (type == value_t::array) {
211             for (auto &item : value) {
212                 if (item.type() == value_t::string) {
213                     item = CheckAndDoApiMapping(item.get<string>(), '#', new2OldApiMap_);
214                 }
215             }
216         }
217     }
218 
Get()219     FrontendApiServer &FrontendApiServer::Get()
220     {
221         static FrontendApiServer singleton;
222         return singleton;
223     }
224 
AddHandler(string_view apiId,ApiInvokeHandler handler)225     void FrontendApiServer::AddHandler(string_view apiId, ApiInvokeHandler handler)
226     {
227         if (handler == nullptr) {
228             return;
229         }
230         handlers_.insert(make_pair(apiId, handler));
231     }
232 
HasHandlerFor(std::string_view apiId) const233     bool FrontendApiServer::HasHandlerFor(std::string_view apiId) const
234     {
235         string apiIdstr = CheckAndDoApiMapping(apiId, '.', old2NewApiMap_);
236         return handlers_.find(apiIdstr) != handlers_.end();
237     }
238 
RemoveHandler(string_view apiId)239     void FrontendApiServer::RemoveHandler(string_view apiId)
240     {
241         handlers_.erase(string(apiId));
242     }
243 
AddCommonPreprocessor(string_view name,ApiInvokeHandler processor)244     void FrontendApiServer::AddCommonPreprocessor(string_view name, ApiInvokeHandler processor)
245     {
246         if (processor == nullptr) {
247             return;
248         }
249         commonPreprocessors_.insert(make_pair(name, processor));
250     }
251 
RemoveCommonPreprocessor(string_view name)252     void FrontendApiServer::RemoveCommonPreprocessor(string_view name)
253     {
254         commonPreprocessors_.erase(string(name));
255     }
256 
Call(const ApiCallInfo & in,ApiReplyInfo & out) const257     void FrontendApiServer::Call(const ApiCallInfo &in, ApiReplyInfo &out) const
258     {
259         auto call = in;
260         // initialize method signature
261         if (sApiArgTypesMap.empty()) {
262             ParseFrontendMethodsSignature();
263         }
264         string oldApiName = ApiMapPre(call);
265         auto find = handlers_.find(call.apiId_);
266         if (find == handlers_.end()) {
267             out.exception_ = ApiCallErr(ERR_INTERNAL, "No handler found for api '" + call.apiId_ + "'");
268             return;
269         }
270         try {
271             for (auto &[name, processor] : commonPreprocessors_) {
272                 processor(call, out);
273                 if (out.exception_.code_ != NO_ERROR) {
274                     out.exception_.message_ = out.exception_.message_ + "(PreProcessing: " + name + ")";
275                     if (oldApiName.length() > 0) {
276                         ApiMapPost(oldApiName, out);
277                     }
278                     return; // error during pre-processing, abort
279                 }
280             }
281         } catch (std::exception &ex) {
282             out.exception_ = ApiCallErr(ERR_INTERNAL, "Preprocessor failed: " + string(ex.what()));
283         }
284         try {
285             find->second(call, out);
286         } catch (std::exception &ex) {
287             // catch possible json-parsing error
288             out.exception_ = ApiCallErr(ERR_INTERNAL, "Handler failed: " + string(ex.what()));
289         }
290         if (oldApiName.length() > 0) {
291             ApiMapPost(oldApiName, out);
292         }
293     }
294 
ApiTransact(const ApiCallInfo & in,ApiReplyInfo & out)295     void ApiTransact(const ApiCallInfo &in, ApiReplyInfo &out)
296     {
297         LOG_D("Begin to invoke api '%{public}s'", in.apiId_.data());
298         FrontendApiServer::Get().Call(in, out);
299     }
300 
301     /** Backend objects cache.*/
302     static map<string, unique_ptr<BackendClass>> sBackendObjects;
303     /** UiDriver binding map.*/
304     static map<string, string> sDriverBindingMap;
305 
306 
307 #define CHECK_CALL_ARG(condition, code, message, error) \
308     if (!(condition)) {                                 \
309         error = ApiCallErr((code), (message));          \
310         return;                                         \
311     }
312 
313     /** Check if the json value represents and illegal data of expected type.*/
CheckCallArgType(string_view expect,const json & value,ApiCallErr & error)314     static void CheckCallArgType(string_view expect, const json &value, ApiCallErr &error)
315     {
316         const auto type = value.type();
317         const auto isInteger = type == value_t::number_integer || type == value_t::number_unsigned;
318         auto begin0 = FRONTEND_CLASS_DEFS.begin();
319         auto end0 = FRONTEND_CLASS_DEFS.end();
320         auto begin1 = FRONTEND_JSON_DEFS.begin();
321         auto end1 = FRONTEND_JSON_DEFS.end();
322         auto find0 = find_if(begin0, end0, [&expect](const FrontEndClassDef *def) { return def->name_ == expect; });
323         auto find1 = find_if(begin1, end1, [&expect](const FrontEndJsonDef *def) { return def->name_ == expect; });
324         if (expect == "int") {
325             CHECK_CALL_ARG(isInteger, ERR_INVALID_INPUT, "Expect integer", error);
326         } else if (expect == "float") {
327             CHECK_CALL_ARG(isInteger || type == value_t::number_float, ERR_INVALID_INPUT, "Expect float", error);
328         } else if (expect == "bool") {
329             CHECK_CALL_ARG(type == value_t::boolean, ERR_INVALID_INPUT, "Expect boolean", error);
330         } else if (expect == "string") {
331             CHECK_CALL_ARG(type == value_t::string, ERR_INVALID_INPUT, "Expect string", error);
332         } else if (find0 != end0) {
333             CHECK_CALL_ARG(type == value_t::string, ERR_INVALID_INPUT, "Expect " + string(expect), error);
334             const auto findRef = sBackendObjects.find(value.get<string>());
335             CHECK_CALL_ARG(findRef != sBackendObjects.end(), ERR_INTERNAL, "Bad object ref", error);
336         } else if (find1 != end1) {
337             CHECK_CALL_ARG(type == value_t::object, ERR_INVALID_INPUT, "Expect " + string(expect), error);
338             auto copy = value;
339             for (size_t idx = 0; idx < (*find1)->propCount_; idx++) {
340                 auto def = (*find1)->props_ + idx;
341                 const auto propName = string(def->name_);
342                 if (!value.contains(propName)) {
343                     CHECK_CALL_ARG(!(def->required_), ERR_INVALID_INPUT, "Missing property " + propName, error);
344                     continue;
345                 }
346                 copy.erase(propName);
347                 // check json property value type recursive
348                 CheckCallArgType(def->type_, value[propName], error);
349                 if (error.code_ != NO_ERROR) {
350                     error.message_ = "Illegal value of property '" + propName + "': " + error.message_;
351                     return;
352                 }
353             }
354             CHECK_CALL_ARG(copy.empty(), ERR_INVALID_INPUT, "Illegal property of " + string(expect), error);
355         } else {
356             CHECK_CALL_ARG(false, ERR_INTERNAL, "Unknown target type " + string(expect), error);
357         }
358     }
359 
360     /** Checks ApiCallInfo data, deliver exception and abort invocation if check fails.*/
APiCallInfoChecker(const ApiCallInfo & in,ApiReplyInfo & out)361     static void APiCallInfoChecker(const ApiCallInfo &in, ApiReplyInfo &out)
362     {
363         // return nullptr by default
364         out.resultValue_ = nullptr;
365         const auto find = sApiArgTypesMap.find(in.apiId_);
366         if (find == sApiArgTypesMap.end()) {
367             return;
368         }
369         const auto &types = find->second.first;
370         const auto argSupportDefault = find->second.second;
371         // check argument count.(last item of "types" is return value type)
372         const auto maxArgc = types.size() - 1;
373         const auto minArgc = argSupportDefault ? maxArgc - 1 : maxArgc;
374         const auto argc = in.paramList_.size();
375         CHECK_CALL_ARG(argc <= maxArgc && argc >= minArgc, ERR_INVALID_INPUT, "Illegal argument count", out.exception_);
376         // check argument type
377         for (size_t idx = 0; idx < argc; idx++) {
378             CheckCallArgType(types.at(idx), in.paramList_.at(idx), out.exception_);
379             if (out.exception_.code_ != NO_ERROR) {
380                 out.exception_.message_ = "Check arg" + to_string(idx) + " failed: " + out.exception_.message_;
381                 return;
382             }
383         }
384     }
385 
386     /** Store the backend object and return the reference-id.*/
StoreBackendObject(unique_ptr<BackendClass> ptr,string_view ownerRef="")387     static string StoreBackendObject(unique_ptr<BackendClass> ptr, string_view ownerRef = "")
388     {
389         static map<string, uint32_t> sObjectCounts;
390         DCHECK(ptr != nullptr);
391         const auto typeName = string(ptr->GetFrontendClassDef().name_);
392         auto find = sObjectCounts.find(typeName);
393         uint32_t index = 0;
394         if (find != sObjectCounts.end()) {
395             index = find->second;
396         }
397         auto ref = typeName + "#" + to_string(index);
398         sObjectCounts[typeName] = index + 1;
399         sBackendObjects[ref] = move(ptr);
400         if (!ownerRef.empty()) {
401             DCHECK(sBackendObjects.find(string(ownerRef)) != sBackendObjects.end());
402             sDriverBindingMap[ref] = ownerRef;
403         }
404         return ref;
405     }
406 
407     /** Retrieve the stored backend object by reference-id.*/
408     template <typename T, typename = enable_if<is_base_of_v<BackendClass, T>>>
GetBackendObject(string_view ref)409     static T &GetBackendObject(string_view ref)
410     {
411         auto find = sBackendObjects.find(string(ref));
412         DCHECK(find != sBackendObjects.end() && find->second != nullptr);
413         return *(reinterpret_cast<T *>(find->second.get()));
414     }
415 
GetBoundUiDriver(string_view ref)416     static UiDriver &GetBoundUiDriver(string_view ref)
417     {
418         auto find0 = sDriverBindingMap.find(string(ref));
419         DCHECK(find0 != sDriverBindingMap.end());
420         auto find1 = sBackendObjects.find(find0->second);
421         DCHECK(find1 != sBackendObjects.end() && find1->second != nullptr);
422         return *(reinterpret_cast<UiDriver *>(find1->second.get()));
423     }
424 
425     /** Delete stored backend objects.*/
BackendObjectsCleaner(const ApiCallInfo & in,ApiReplyInfo & out)426     static void BackendObjectsCleaner(const ApiCallInfo &in, ApiReplyInfo &out)
427     {
428         stringstream ss("Deleted objects[");
429         DCHECK(in.paramList_.type() == value_t::array);
430         for (const auto &item : in.paramList_) {
431             DCHECK(item.type() == value_t::string); // must be objRef
432             const auto ref = item.get<string>();
433             auto findBinding = sDriverBindingMap.find(ref);
434             if (findBinding != sDriverBindingMap.end()) {
435                 sDriverBindingMap.erase(findBinding);
436             }
437             auto findObject = sBackendObjects.find(ref);
438             if (findObject == sBackendObjects.end()) {
439                 LOG_W("No such object living: %{public}s", ref.c_str());
440                 continue;
441             }
442             sBackendObjects.erase(findObject);
443             ss << ref << ",";
444         }
445         ss << "]";
446         LOG_D("%{public}s", ss.str().c_str());
447     }
448 
ReadCallArg(const ApiCallInfo & in,size_t index)449     template <typename T> static T ReadCallArg(const ApiCallInfo &in, size_t index)
450     {
451         DCHECK(in.paramList_.type() == value_t::array);
452         DCHECK(index <= in.paramList_.size());
453         return in.paramList_.at(index).get<T>();
454     }
455 
ReadCallArg(const ApiCallInfo & in,size_t index,T defValue)456     template <typename T> static T ReadCallArg(const ApiCallInfo &in, size_t index, T defValue)
457     {
458         DCHECK(in.paramList_.type() == value_t::array);
459         if (index >= in.paramList_.size()) {
460             return defValue;
461         }
462         return in.paramList_.at(index).get<T>();
463     }
464 
GenericOnAttrBuilder(const ApiCallInfo & in,ApiReplyInfo & out)465     template <UiAttr kAttr, typename T> static void GenericOnAttrBuilder(const ApiCallInfo &in, ApiReplyInfo &out)
466     {
467         const auto attrName = ATTR_NAMES[kAttr];
468         // always create and return a new selector
469         auto selector = make_unique<WidgetSelector>();
470         if (in.callerObjRef_ != REF_SEED_ON) { // copy-construct from the caller if it's not seed
471             *selector = GetBackendObject<WidgetSelector>(in.callerObjRef_);
472         }
473         string testValue = "";
474         if constexpr (std::is_same<string, T>::value) {
475             testValue = ReadCallArg<string>(in, INDEX_ZERO);
476         } else if constexpr (std::is_same<bool, T>::value) { // bool testValue can be defaulted to true
477             testValue = ReadCallArg<bool>(in, INDEX_ZERO, true) ? "true" : "false";
478         } else {
479             testValue = to_string(ReadCallArg<T>(in, INDEX_ZERO));
480         }
481         auto matchPattern = ReadCallArg<uint8_t>(in, INDEX_ONE, ValueMatchPattern::EQ); // match pattern argument
482         auto matcher = WidgetAttrMatcher(attrName, testValue, static_cast<ValueMatchPattern>(matchPattern));
483         selector->AddMatcher(matcher);
484         out.resultValue_ = StoreBackendObject(move(selector));
485     }
486 
RegisterOnBuilders()487     static void RegisterOnBuilders()
488     {
489         auto &server = FrontendApiServer::Get();
490         server.AddHandler("On.accessibilityId", GenericOnAttrBuilder<UiAttr::ACCESSIBILITY_ID, int32_t>);
491         server.AddHandler("On.text", GenericOnAttrBuilder<UiAttr::TEXT, string>);
492         server.AddHandler("On.id", GenericOnAttrBuilder<UiAttr::ID, string>);
493         server.AddHandler("On.type", GenericOnAttrBuilder<UiAttr::TYPE, string>);
494         server.AddHandler("On.enabled", GenericOnAttrBuilder<UiAttr::ENABLED, bool>);
495         server.AddHandler("On.focused", GenericOnAttrBuilder<UiAttr::FOCUSED, bool>);
496         server.AddHandler("On.selected", GenericOnAttrBuilder<UiAttr::SELECTED, bool>);
497         server.AddHandler("On.clickable", GenericOnAttrBuilder<UiAttr::CLICKABLE, bool>);
498         server.AddHandler("On.longClickable", GenericOnAttrBuilder<UiAttr::LONG_CLICKABLE, bool>);
499         server.AddHandler("On.scrollable", GenericOnAttrBuilder<UiAttr::SCROLLABLE, bool>);
500         server.AddHandler("On.checkable", GenericOnAttrBuilder<UiAttr::CHECKABLE, bool>);
501         server.AddHandler("On.checked", GenericOnAttrBuilder<UiAttr::CHECKED, bool>);
502 
503         auto genericRelativeBuilder = [](const ApiCallInfo &in, ApiReplyInfo &out) {
504             const auto attrName = in.apiId_.substr(ON_DEF.name_.length() + 1); // On.xxx()->xxx
505             // always create and return a new selector
506             auto selector = make_unique<WidgetSelector>();
507             if (in.callerObjRef_ != REF_SEED_ON) { // copy-construct from the caller if it's not seed
508                 *selector = GetBackendObject<WidgetSelector>(in.callerObjRef_);
509             }
510             if (attrName == "isBefore") {
511                 auto &that = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
512                 selector->AddRearLocator(that, out.exception_);
513             } else {
514                 auto &that = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
515                 selector->AddFrontLocator(that, out.exception_);
516             }
517             out.resultValue_ = StoreBackendObject(move(selector));
518         };
519         server.AddHandler("On.isBefore", genericRelativeBuilder);
520         server.AddHandler("On.isAfter", genericRelativeBuilder);
521     }
522 
RegisterUiDriverComponentFinders()523     static void RegisterUiDriverComponentFinders()
524     {
525         auto &server = FrontendApiServer::Get();
526         auto genericFindWidgetHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
527             const auto driverRef = in.callerObjRef_;
528             auto &driver = GetBackendObject<UiDriver>(driverRef);
529             auto &selector = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
530             UiOpArgs uiOpArgs;
531             vector<unique_ptr<Widget>> recv;
532             if (in.apiId_ == "Driver.waitForComponent") {
533                 uiOpArgs.waitWidgetMaxMs_ = ReadCallArg<uint32_t>(in, INDEX_ONE);
534                 auto result = driver.WaitForWidget(selector, uiOpArgs, out.exception_);
535                 if (result != nullptr) {
536                     recv.emplace_back(move(result));
537                 }
538             } else {
539                 driver.FindWidgets(selector, recv, out.exception_);
540             }
541             if (out.exception_.code_ != NO_ERROR) {
542                 return;
543             }
544             if (in.apiId_ == "Driver.assertComponentExist") {
545                 if (recv.empty()) { // widget-exist assertion failure, deliver exception
546                     out.exception_.code_ = ERR_ASSERTION_FAILED;
547                     out.exception_.message_ = "Component not exist matching: " + selector.Describe();
548                 }
549             } else if (in.apiId_ == "Driver.findComponents") { // return widget array, maybe empty
550                 for (auto &ptr : recv) {
551                     out.resultValue_.emplace_back(StoreBackendObject(move(ptr), driverRef));
552                 }
553             } else if (recv.empty()) { // return first one or null
554                 out.resultValue_ = nullptr;
555             } else {
556                 out.resultValue_ = StoreBackendObject(move(*(recv.begin())), driverRef);
557             }
558         };
559         server.AddHandler("Driver.findComponent", genericFindWidgetHandler);
560         server.AddHandler("Driver.findComponents", genericFindWidgetHandler);
561         server.AddHandler("Driver.waitForComponent", genericFindWidgetHandler);
562         server.AddHandler("Driver.assertComponentExist", genericFindWidgetHandler);
563     }
564 
RegisterUiDriverWindowFinder()565     static void RegisterUiDriverWindowFinder()
566     {
567         auto findWindowHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
568             const auto driverRef = in.callerObjRef_;
569             auto &driver = GetBackendObject<UiDriver>(driverRef);
570             auto filterJson = ReadCallArg<json>(in, INDEX_ZERO);
571             if (filterJson.empty()) {
572                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "WindowFilter cannot be empty");
573                 return;
574             }
575             auto matcher = [&filterJson](const Window &window) -> bool {
576                 bool match = true;
577                 if (filterJson.contains("bundleName")) {
578                     match = match && (filterJson["bundleName"].get<string>() == window.bundleName_);
579                 }
580                 if (filterJson.contains("title")) {
581                     match = match && (filterJson["title"].get<string>() == window.title_);
582                 }
583                 if (filterJson.contains("focused")) {
584                     match = match && (filterJson["focused"].get<bool>() == window.focused_);
585                 }
586                 if (filterJson.contains("actived")) {
587                     match = match && (filterJson["actived"].get<bool>() == window.actived_);
588                 }
589                 return match;
590             };
591             auto window = driver.FindWindow(matcher, out.exception_);
592             if (window == nullptr) {
593                 out.resultValue_ = nullptr;
594             } else {
595                 out.resultValue_ = StoreBackendObject(move(window), driverRef);
596             }
597         };
598         FrontendApiServer::Get().AddHandler("Driver.findWindow", findWindowHandler);
599     }
600 
RegisterUiDriverMiscMethods()601     static void RegisterUiDriverMiscMethods()
602     {
603         auto &server = FrontendApiServer::Get();
604         auto create = [](const ApiCallInfo &in, ApiReplyInfo &out) {
605             auto driver = make_unique<UiDriver>();
606             driver->GetUiController(out.exception_);
607             if (out.exception_.code_ == NO_ERROR) {
608                 out.resultValue_ = StoreBackendObject(move(driver));
609             } else {
610                 out.exception_ = ApiCallErr(ERR_INITIALIZE_FAILED);
611             }
612         };
613         server.AddHandler("Driver.create", create);
614 
615         auto delay = [](const ApiCallInfo &in, ApiReplyInfo &out) {
616             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
617             driver.DelayMs(ReadCallArg<uint32_t>(in, INDEX_ZERO));
618         };
619         server.AddHandler("Driver.delayMs", delay);
620 
621         auto screenCap = [](const ApiCallInfo &in, ApiReplyInfo &out) {
622             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
623             driver.TakeScreenCap(ReadCallArg<string>(in, INDEX_ZERO), out.exception_);
624             out.resultValue_ = (out.exception_.code_ == NO_ERROR);
625             out.exception_.code_ = NO_ERROR;
626         };
627         server.AddHandler("Driver.screenCap", screenCap);
628 
629         auto pressBack = [](const ApiCallInfo &in, ApiReplyInfo &out) {
630             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
631             UiOpArgs uiOpArgs;
632             driver.TriggerKey(Back(), uiOpArgs, out.exception_);
633         };
634         server.AddHandler("Driver.pressBack", pressBack);
635         auto pressHome = [](const ApiCallInfo &in, ApiReplyInfo &out) {
636             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
637             UiOpArgs uiOpArgs;
638             driver.TriggerKey(Home(), uiOpArgs, out.exception_);
639         };
640         server.AddHandler("Driver.pressHome", pressHome);
641         auto triggerKey = [](const ApiCallInfo &in, ApiReplyInfo &out) {
642             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
643             UiOpArgs uiOpArgs;
644             auto key = AnonymousSingleKey(ReadCallArg<int32_t>(in, INDEX_ZERO));
645             driver.TriggerKey(key, uiOpArgs, out.exception_);
646         };
647         server.AddHandler("Driver.triggerKey", triggerKey);
648         auto triggerCombineKeys = [](const ApiCallInfo &in, ApiReplyInfo &out) {
649             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
650             UiOpArgs uiOpArgs;
651             auto key0 = ReadCallArg<int32_t>(in, INDEX_ZERO);
652             auto key1 = ReadCallArg<int32_t>(in, INDEX_ONE);
653             auto key2 = ReadCallArg<int32_t>(in, INDEX_TWO, KEYCODE_NONE);
654             auto keyAction = CombinedKeys(key0, key1, key2);
655             driver.TriggerKey(keyAction, uiOpArgs, out.exception_);
656         };
657         server.AddHandler("Driver.triggerCombineKeys", triggerCombineKeys);
658     }
659 
CheckSwipeVelocityPps(UiOpArgs & args)660     static void CheckSwipeVelocityPps(UiOpArgs& args)
661     {
662         if (args.swipeVelocityPps_ < args.minSwipeVelocityPps_ || args.swipeVelocityPps_ > args.maxSwipeVelocityPps_) {
663             LOG_W("The swipe velocity out of range");
664             args.swipeVelocityPps_ = args.defaultSwipeVelocityPps_;
665         }
666     }
667 
RegisterUiDriverTouchOperators()668     static void RegisterUiDriverTouchOperators()
669     {
670         auto &server = FrontendApiServer::Get();
671         auto genericClick = [](const ApiCallInfo &in, ApiReplyInfo &out) {
672             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
673             const auto point0 = Point(ReadCallArg<int32_t>(in, INDEX_ZERO), ReadCallArg<int32_t>(in, INDEX_ONE));
674             auto point1 = Point(0, 0);
675             UiOpArgs uiOpArgs;
676             auto op = TouchOp::CLICK;
677             if (in.apiId_ == "Driver.longClick") {
678                 op = TouchOp::LONG_CLICK;
679             } else if (in.apiId_ == "Driver.doubleClick") {
680                 op = TouchOp::DOUBLE_CLICK_P;
681             } else if (in.apiId_ == "Driver.swipe") {
682                 op = TouchOp::SWIPE;
683                 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_FOUR, uiOpArgs.swipeVelocityPps_);
684                 CheckSwipeVelocityPps(uiOpArgs);
685                 point1 = Point(ReadCallArg<int32_t>(in, INDEX_TWO), ReadCallArg<int32_t>(in, INDEX_THREE));
686             } else if (in.apiId_ == "Driver.drag") {
687                 op = TouchOp::DRAG;
688                 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_FOUR, uiOpArgs.swipeVelocityPps_);
689                 CheckSwipeVelocityPps(uiOpArgs);
690                 point1 = Point(ReadCallArg<int32_t>(in, INDEX_TWO), ReadCallArg<int32_t>(in, INDEX_THREE));
691             }
692             if (op == TouchOp::SWIPE || op == TouchOp::DRAG) {
693                 auto touch = GenericSwipe(op, point0, point1);
694                 driver.PerformTouch(touch, uiOpArgs, out.exception_);
695             } else {
696                 auto touch = GenericClick(op, point0);
697                 driver.PerformTouch(touch, uiOpArgs, out.exception_);
698             }
699         };
700         server.AddHandler("Driver.click", genericClick);
701         server.AddHandler("Driver.longClick", genericClick);
702         server.AddHandler("Driver.doubleClick", genericClick);
703         server.AddHandler("Driver.swipe", genericClick);
704         server.AddHandler("Driver.drag", genericClick);
705     }
706 
CheckMultiPointerOperatorsPoint(const PointerMatrix & pointer)707     static bool CheckMultiPointerOperatorsPoint(const PointerMatrix& pointer)
708     {
709         for (uint32_t fingerIndex = 0; fingerIndex < pointer.GetFingers(); fingerIndex++) {
710             for (uint32_t stepIndex = 0; stepIndex < pointer.GetSteps(); stepIndex++) {
711                 if (pointer.At(fingerIndex, stepIndex).flags_ != 1) {
712                     return false;
713                 }
714             }
715         }
716         return true;
717     }
718 
RegisterUiDriverMultiPointerOperators()719     static void RegisterUiDriverMultiPointerOperators()
720     {
721         auto &server = FrontendApiServer::Get();
722         auto genericFling = [](const ApiCallInfo &in, ApiReplyInfo &out) {
723             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
724             UiOpArgs uiOpArgs;
725             auto op = TouchOp::SWIPE;
726             auto pointJson0 = ReadCallArg<json>(in, INDEX_ZERO);
727             auto pointJson1 = ReadCallArg<json>(in, INDEX_ONE);
728             if (pointJson0.empty() || pointJson1.empty()) {
729                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Point cannot be empty");
730                 return;
731             }
732             const auto point0 = Point(pointJson0["x"], pointJson0["y"]);
733             const auto point1 = Point(pointJson1["x"], pointJson1["y"]);
734             const auto stepLength = ReadCallArg<uint32_t>(in, INDEX_TWO);
735             uiOpArgs.swipeVelocityPps_  = ReadCallArg<uint32_t>(in, INDEX_THREE);
736             CheckSwipeVelocityPps(uiOpArgs);
737             const int32_t distanceX = point1.px_ - point0.px_;
738             const int32_t distanceY = point1.py_ - point0.py_;
739             const uint32_t distance = sqrt(distanceX * distanceX + distanceY * distanceY);
740             if (stepLength <= 0 || stepLength > distance) {
741                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "The stepLen is out of range");
742                 return;
743             }
744             uiOpArgs.swipeStepsCounts_ = distance / stepLength;
745             auto touch = GenericSwipe(op, point0, point1);
746             driver.PerformTouch(touch, uiOpArgs, out.exception_);
747         };
748         server.AddHandler("Driver.fling", genericFling);
749 
750         auto multiPointerAction = [](const ApiCallInfo &in, ApiReplyInfo &out) {
751             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
752             auto &pointer = GetBackendObject<PointerMatrix>(ReadCallArg<string>(in, INDEX_ZERO));
753             auto flag = CheckMultiPointerOperatorsPoint(pointer);
754             if (!flag) {
755                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "There is not all coordinate points are set");
756                 return;
757             }
758             UiOpArgs uiOpArgs;
759             uiOpArgs.swipeVelocityPps_  = ReadCallArg<uint32_t>(in, INDEX_ONE, uiOpArgs.swipeVelocityPps_);
760             CheckSwipeVelocityPps(uiOpArgs);
761             auto touch = MultiPointerAction(pointer);
762             driver.PerformTouch(touch, uiOpArgs, out.exception_);
763             out.resultValue_ = (out.exception_.code_ == NO_ERROR);
764         };
765         server.AddHandler("Driver.injectMultiPointerAction", multiPointerAction);
766     }
767 
RegisterUiDriverDisplayOperators()768     static void RegisterUiDriverDisplayOperators()
769     {
770         auto &server = FrontendApiServer::Get();
771         auto genericDisplayOperator = [](const ApiCallInfo &in, ApiReplyInfo &out) {
772             auto &driver = GetBackendObject<UiDriver>(in.callerObjRef_);
773             auto controller = driver.GetUiController(out.exception_);
774             if (out.exception_.code_ != NO_ERROR) {
775                 return;
776             }
777             if (in.apiId_ == "Driver.setDisplayRotation") {
778                 auto rotation = ReadCallArg<DisplayRotation>(in, INDEX_ZERO);
779                 controller->SetDisplayRotation(rotation);
780             } else if (in.apiId_ == "Driver.getDisplayRotation") {
781                 out.resultValue_ = controller->GetDisplayRotation();
782             } else if (in.apiId_ == "Driver.setDisplayRotationEnabled") {
783                 auto enabled = ReadCallArg<bool>(in, INDEX_ZERO);
784                 controller->SetDisplayRotationEnabled(enabled);
785             } else if (in.apiId_ == "Driver.waitForIdle") {
786                 auto idleTime = ReadCallArg<uint32_t>(in, INDEX_ZERO);
787                 auto timeout = ReadCallArg<uint32_t>(in, INDEX_ONE);
788                 out.resultValue_ = controller->WaitForUiSteady(idleTime, timeout);
789             } else if (in.apiId_ == "Driver.wakeUpDisplay") {
790                 if (controller->IsScreenOn()) {
791                     return;
792                 } else {
793                     LOG_I("screen is off, turn it on");
794                     UiOpArgs uiOpArgs;
795                     driver.TriggerKey(Power(), uiOpArgs, out.exception_);
796                 }
797             } else if (in.apiId_ == "Driver.getDisplaySize") {
798                 auto result = controller->GetDisplaySize();
799                 json data;
800                 data["x"] = result.px_;
801                 data["y"] = result.py_;
802                 out.resultValue_ = data;
803             } else if (in.apiId_ == "Driver.getDisplayDensity") {
804                 auto result = controller->GetDisplayDensity();
805                 json data;
806                 data["x"] = result.px_;
807                 data["y"] = result.py_;
808                 out.resultValue_ = data;
809             }
810         };
811         server.AddHandler("Driver.setDisplayRotation", genericDisplayOperator);
812         server.AddHandler("Driver.getDisplayRotation", genericDisplayOperator);
813         server.AddHandler("Driver.setDisplayRotationEnabled", genericDisplayOperator);
814         server.AddHandler("Driver.waitForIdle", genericDisplayOperator);
815         server.AddHandler("Driver.wakeUpDisplay", genericDisplayOperator);
816         server.AddHandler("Driver.getDisplaySize", genericDisplayOperator);
817         server.AddHandler("Driver.getDisplayDensity", genericDisplayOperator);
818     }
819 
820     template <UiAttr kAttr, bool kString = false>
GenericComponentAttrGetter(const ApiCallInfo & in,ApiReplyInfo & out)821     static void GenericComponentAttrGetter(const ApiCallInfo &in, ApiReplyInfo &out)
822     {
823         constexpr auto attrName = ATTR_NAMES[kAttr];
824         auto &image = GetBackendObject<Widget>(in.callerObjRef_);
825         auto &driver = GetBoundUiDriver(in.callerObjRef_);
826         auto snapshot = driver.RetrieveWidget(image, out.exception_);
827         if (out.exception_.code_ != NO_ERROR) {
828             out.resultValue_ = nullptr; // exception, return null
829             return;
830         }
831         if (attrName == ATTR_NAMES[UiAttr::BOUNDSCENTER]) { // getBoundsCenter
832             const auto bounds = snapshot->GetBounds();
833             json data;
834             data["x"] = bounds.GetCenterX();
835             data["y"] = bounds.GetCenterY();
836             out.resultValue_ = data;
837             return;
838         }
839         if (attrName == ATTR_NAMES[UiAttr::BOUNDS]) { // getBounds
840             const auto bounds = snapshot->GetBounds();
841             json data;
842             data["left"] = bounds.left_;
843             data["top"] = bounds.top_;
844             data["right"] = bounds.right_;
845             data["bottom"] = bounds.bottom_;
846             out.resultValue_ = data;
847             return;
848         }
849         // convert value-string to json value of target type
850         auto attrValue = snapshot->GetAttr(attrName, "NA");
851         if (attrValue == "NA") {
852             out.resultValue_ = nullptr; // no such attribute, return null
853         } else if (kString) {
854             out.resultValue_ = attrValue;
855         } else {
856             out.resultValue_ = nlohmann::json::parse(attrValue);
857         }
858     }
859 
RegisterUiComponentAttrGetters()860     static void RegisterUiComponentAttrGetters()
861     {
862         auto &server = FrontendApiServer::Get();
863         server.AddHandler("Component.getAccessibilityId", GenericComponentAttrGetter<UiAttr::ACCESSIBILITY_ID>);
864         server.AddHandler("Component.getText", GenericComponentAttrGetter<UiAttr::TEXT, true>);
865         server.AddHandler("Component.getId", GenericComponentAttrGetter<UiAttr::ID, true>);
866         server.AddHandler("Component.getType", GenericComponentAttrGetter<UiAttr::TYPE, true>);
867         server.AddHandler("Component.isEnabled", GenericComponentAttrGetter<UiAttr::ENABLED>);
868         server.AddHandler("Component.isFocused", GenericComponentAttrGetter<UiAttr::FOCUSED>);
869         server.AddHandler("Component.isSelected", GenericComponentAttrGetter<UiAttr::SELECTED>);
870         server.AddHandler("Component.isClickable", GenericComponentAttrGetter<UiAttr::CLICKABLE>);
871         server.AddHandler("Component.isLongClickable", GenericComponentAttrGetter<UiAttr::LONG_CLICKABLE>);
872         server.AddHandler("Component.isScrollable", GenericComponentAttrGetter<UiAttr::SCROLLABLE>);
873         server.AddHandler("Component.isCheckable", GenericComponentAttrGetter<UiAttr::CHECKABLE>);
874         server.AddHandler("Component.isChecked", GenericComponentAttrGetter<UiAttr::CHECKED>);
875         server.AddHandler("Component.getBounds", GenericComponentAttrGetter<UiAttr::BOUNDS>);
876         server.AddHandler("Component.getBoundsCenter", GenericComponentAttrGetter<UiAttr::BOUNDSCENTER>);
877     }
878 
RegisterUiComponentOperators()879     static void RegisterUiComponentOperators()
880     {
881         auto &server = FrontendApiServer::Get();
882         auto genericOperationHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
883             auto &widget = GetBackendObject<Widget>(in.callerObjRef_);
884             auto &driver = GetBoundUiDriver(in.callerObjRef_);
885             UiOpArgs uiOpArgs;
886             auto wOp = WidgetOperator(driver, widget, uiOpArgs);
887             if (in.apiId_ == "Component.click") {
888                 wOp.GenericClick(TouchOp::CLICK, out.exception_);
889             } else if (in.apiId_ == "Component.longClick") {
890                 wOp.GenericClick(TouchOp::LONG_CLICK, out.exception_);
891             } else if (in.apiId_ == "Component.doubleClick") {
892                 wOp.GenericClick(TouchOp::DOUBLE_CLICK_P, out.exception_);
893             } else if (in.apiId_ == "Component.scrollToTop") {
894                 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_ZERO, uiOpArgs.swipeVelocityPps_);
895                 CheckSwipeVelocityPps(uiOpArgs);
896                 wOp.ScrollToEnd(true, out.exception_);
897             } else if (in.apiId_ == "Component.scrollToBottom") {
898                 uiOpArgs.swipeVelocityPps_ = ReadCallArg<uint32_t>(in, INDEX_ZERO, uiOpArgs.swipeVelocityPps_);
899                 CheckSwipeVelocityPps(uiOpArgs);
900                 wOp.ScrollToEnd(false, out.exception_);
901             } else if (in.apiId_ == "Component.dragTo") {
902                 auto &widgetTo = GetBackendObject<Widget>(ReadCallArg<string>(in, INDEX_ZERO));
903                 wOp.DragIntoWidget(widgetTo, out.exception_);
904             } else if (in.apiId_ == "Component.inputText") {
905                 wOp.InputText(ReadCallArg<string>(in, INDEX_ZERO), out.exception_);
906             } else if (in.apiId_ == "Component.clearText") {
907                 wOp.InputText("", out.exception_);
908             } else if (in.apiId_ == "Component.scrollSearch") {
909                 auto &selector = GetBackendObject<WidgetSelector>(ReadCallArg<string>(in, INDEX_ZERO));
910                 auto res = wOp.ScrollFindWidget(selector, out.exception_);
911                 if (res != nullptr) {
912                     out.resultValue_ = StoreBackendObject(move(res), sDriverBindingMap.find(in.callerObjRef_)->second);
913                 }
914             } else if (in.apiId_ == "Component.pinchOut" || in.apiId_ == "Component.pinchIn") {
915                 auto pinchScale = ReadCallArg<float_t>(in, INDEX_ZERO);
916                 wOp.PinchWidget(pinchScale, out.exception_);
917             }
918         };
919         server.AddHandler("Component.click", genericOperationHandler);
920         server.AddHandler("Component.longClick", genericOperationHandler);
921         server.AddHandler("Component.doubleClick", genericOperationHandler);
922         server.AddHandler("Component.scrollToTop", genericOperationHandler);
923         server.AddHandler("Component.scrollToBottom", genericOperationHandler);
924         server.AddHandler("Component.dragTo", genericOperationHandler);
925         server.AddHandler("Component.inputText", genericOperationHandler);
926         server.AddHandler("Component.clearText", genericOperationHandler);
927         server.AddHandler("Component.scrollSearch", genericOperationHandler);
928         server.AddHandler("Component.pinchOut", genericOperationHandler);
929         server.AddHandler("Component.pinchIn", genericOperationHandler);
930     }
931 
RegisterUiWindowAttrGetters()932     static void RegisterUiWindowAttrGetters()
933     {
934         auto &server = FrontendApiServer::Get();
935         auto genericGetter = [](const ApiCallInfo &in, ApiReplyInfo &out) {
936             auto &window = GetBackendObject<Window>(in.callerObjRef_);
937             auto &driver = GetBoundUiDriver(in.callerObjRef_);
938             auto snapshot = driver.RetrieveWindow(window, out.exception_);
939             if (out.exception_.code_ != NO_ERROR) {
940                 out.resultValue_ = nullptr; // exception, return null
941                 return;
942             }
943             if (in.apiId_ == "UiWindow.getBundleName") {
944                 out.resultValue_ = snapshot->bundleName_;
945             } else if (in.apiId_ == "UiWindow.getBounds") {
946                 json data;
947                 data["left"] = snapshot->bounds_.left_;
948                 data["top"] = snapshot->bounds_.top_;
949                 data["right"] = snapshot->bounds_.right_;
950                 data["bottom"] = snapshot->bounds_.bottom_;
951                 out.resultValue_ = data;
952             } else if (in.apiId_ == "UiWindow.getTitle") {
953                 out.resultValue_ = snapshot->title_;
954             } else if (in.apiId_ == "UiWindow.getWindowMode") {
955                 out.resultValue_ = (uint8_t)(snapshot->mode_ - 1);
956             } else if (in.apiId_ == "UiWindow.isFocused") {
957                 out.resultValue_ = snapshot->focused_;
958             } else if (in.apiId_ == "UiWindow.isActived") {
959                 out.resultValue_ = snapshot->actived_;
960             }
961         };
962         server.AddHandler("UiWindow.getBundleName", genericGetter);
963         server.AddHandler("UiWindow.getBounds", genericGetter);
964         server.AddHandler("UiWindow.getTitle", genericGetter);
965         server.AddHandler("UiWindow.getWindowMode", genericGetter);
966         server.AddHandler("UiWindow.isFocused", genericGetter);
967         server.AddHandler("UiWindow.isActived", genericGetter);
968     }
969 
RegisterUiWindowOperators()970     static void RegisterUiWindowOperators()
971     {
972         auto &server = FrontendApiServer::Get();
973         auto genericWinOperationHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
974             auto &window = GetBackendObject<Window>(in.callerObjRef_);
975             auto &driver = GetBoundUiDriver(in.callerObjRef_);
976             UiOpArgs uiOpArgs;
977             auto wOp = WindowOperator(driver, window, uiOpArgs);
978             auto action = in.apiId_;
979             if (action == "UiWindow.resize") {
980                 auto width = ReadCallArg<uint32_t>(in, INDEX_ZERO);
981                 auto highth = ReadCallArg<uint32_t>(in, INDEX_ONE);
982                 auto direction = ReadCallArg<ResizeDirection>(in, INDEX_TWO);
983                 wOp.Resize(width, highth, direction, out);
984             } else if (action == "UiWindow.focus") {
985                 wOp.Focus(out);
986             }
987         };
988         server.AddHandler("UiWindow.focus", genericWinOperationHandler);
989         server.AddHandler("UiWindow.resize", genericWinOperationHandler);
990     }
991 
RegisterUiWinBarOperators()992     static void RegisterUiWinBarOperators()
993     {
994         auto &server = FrontendApiServer::Get();
995         auto genericWinBarOperationHandler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
996             auto &window = GetBackendObject<Window>(in.callerObjRef_);
997             auto &driver = GetBoundUiDriver(in.callerObjRef_);
998             UiOpArgs uiOpArgs;
999             auto wOp = WindowOperator(driver, window, uiOpArgs);
1000             auto action = in.apiId_;
1001             if (window.decoratorEnabled_) {
1002                 if (action == "UiWindow.split") {
1003                     wOp.Split(out);
1004                 } else if (action == "UiWindow.maximize") {
1005                     wOp.Maximize(out);
1006                 } else if (action == "UiWindow.resume") {
1007                     wOp.Resume(out);
1008                 } else if (action == "UiWindow.minimize") {
1009                     wOp.Minimize(out);
1010                 } else if (action == "UiWindow.close") {
1011                     wOp.Close(out);
1012                 } else if (action == "UiWindow.moveTo") {
1013                     auto endX = ReadCallArg<uint32_t>(in, INDEX_ZERO);
1014                     auto endY = ReadCallArg<uint32_t>(in, INDEX_ONE);
1015                     wOp.MoveTo(endX, endY, out);
1016                 }
1017             } else {
1018                 out.exception_ = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "this device can not support this action");
1019             }
1020         };
1021         server.AddHandler("UiWindow.split", genericWinBarOperationHandler);
1022         server.AddHandler("UiWindow.maximize", genericWinBarOperationHandler);
1023         server.AddHandler("UiWindow.resume", genericWinBarOperationHandler);
1024         server.AddHandler("UiWindow.minimize", genericWinBarOperationHandler);
1025         server.AddHandler("UiWindow.close", genericWinBarOperationHandler);
1026         server.AddHandler("UiWindow.moveTo", genericWinBarOperationHandler);
1027     }
1028 
RegisterPointerMatrixOperators()1029     static void RegisterPointerMatrixOperators()
1030     {
1031         auto &server = FrontendApiServer::Get();
1032         auto create = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1033             UiOpArgs uiOpArgs;
1034             auto finger = ReadCallArg<uint32_t>(in, INDEX_ZERO);
1035             if (finger < 1 || finger > uiOpArgs.maxMultiTouchFingers) {
1036                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Number of illegal fingers");
1037                 return;
1038             }
1039             auto step = ReadCallArg<uint32_t>(in, INDEX_ONE);
1040             if (step < 1 || step > uiOpArgs.maxMultiTouchSteps) {
1041                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Number of illegal steps");
1042                 return;
1043             }
1044             out.resultValue_ = StoreBackendObject(make_unique<PointerMatrix>(finger, step));
1045         };
1046         server.AddHandler("PointerMatrix.create", create);
1047 
1048         auto setPoint = [](const ApiCallInfo &in, ApiReplyInfo &out) {
1049             auto &pointer = GetBackendObject<PointerMatrix>(in.callerObjRef_);
1050             auto finger = ReadCallArg<uint32_t>(in, INDEX_ZERO);
1051             if (finger < 0 || finger >= pointer.GetFingers()) {
1052                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Number of illegal fingers");
1053                 return;
1054             }
1055             auto step = ReadCallArg<uint32_t>(in, INDEX_ONE);
1056             if (step < 0 || step >= pointer.GetSteps()) {
1057                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Number of illegal steps");
1058                 return;
1059             }
1060             auto pointJson = ReadCallArg<json>(in, INDEX_TWO);
1061             if (pointJson.empty()) {
1062                 out.exception_ = ApiCallErr(ERR_INVALID_INPUT, "Point cannot be empty");
1063                 return;
1064             }
1065             const auto point = Point(pointJson["x"], pointJson["y"]);
1066             pointer.At(finger, step).point_ = point;
1067             pointer.At(finger, step).flags_ = 1;
1068         };
1069         server.AddHandler("PointerMatrix.setPoint", setPoint);
1070     }
1071 
1072     /** Register frontendApiHandlers and preprocessors on startup.*/
RegisterApiHandlers()1073     __attribute__((constructor)) static void RegisterApiHandlers()
1074     {
1075         auto &server = FrontendApiServer::Get();
1076         server.AddCommonPreprocessor("APiCallInfoChecker", APiCallInfoChecker);
1077         server.AddHandler("BackendObjectsCleaner", BackendObjectsCleaner);
1078         RegisterOnBuilders();
1079         RegisterUiDriverComponentFinders();
1080         RegisterUiDriverWindowFinder();
1081         RegisterUiDriverMiscMethods();
1082         RegisterUiDriverTouchOperators();
1083         RegisterUiComponentAttrGetters();
1084         RegisterUiComponentOperators();
1085         RegisterUiWindowAttrGetters();
1086         RegisterUiWindowOperators();
1087         RegisterUiWinBarOperators();
1088         RegisterPointerMatrixOperators();
1089         RegisterUiDriverMultiPointerOperators();
1090         RegisterUiDriverDisplayOperators();
1091     }
1092 } // namespace OHOS::uitest
1093