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