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