1 /* 2 * Copyright (c) 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 #include <chrono> 16 #include <thread> 17 #include "external_calls.h" 18 #include "ui_record.h" 19 20 namespace OHOS::uitest { 21 using namespace std; 22 using namespace std::chrono; 23 using nlohmann::json; 24 25 static bool g_uiRecordRun = false; 26 std::string ts; 27 std::string savePath; 28 int operationCount = 0; 29 int g_callBackId = -1; 30 int64_t g_downTime = 0; 31 static std::shared_ptr<InputEventCallback> g_uiCallBackInstance = nullptr; 32 const std::map <int32_t, TouchOpt> SPECIAL_KET_MAP = { 33 {MMI::KeyEvent::KEYCODE_BACK, TouchOpt::OP_RETURN}, 34 {MMI::KeyEvent::KEYCODE_HOME, TouchOpt::OP_HOME}, 35 }; 36 37 static std::vector<SubscribeKeyevent> NEED_SUBSCRIBE_KEY = { 38 {MMI::KeyEvent::KEYCODE_POWER, true, 0}, // 电源键按下订阅 39 {MMI::KeyEvent::KEYCODE_POWER, false, 0}, // 电源键抬起订阅 40 {MMI::KeyEvent::KEYCODE_VOLUME_UP, true, 0}, // 音量UP键按下订阅 41 {MMI::KeyEvent::KEYCODE_VOLUME_DOWN, true, 0}, // 音量DOWN键按下订阅 42 {MMI::KeyEvent::KEYCODE_ESCAPE, true, 0}, // esc键按下订阅 43 {MMI::KeyEvent::KEYCODE_ESCAPE, false, 0}, // esc键抬起订阅 44 {MMI::KeyEvent::KEYCODE_F1, true, 0}, // f1键按下订阅 45 {MMI::KeyEvent::KEYCODE_F1, false, 0}, // f1键抬起订阅 46 {MMI::KeyEvent::KEYCODE_ALT_LEFT, true, 0}, // alt-left键按下订阅 47 {MMI::KeyEvent::KEYCODE_ALT_LEFT, false, 0}, // alt-left键抬起订阅 48 {MMI::KeyEvent::KEYCODE_ALT_RIGHT, true, 0}, // alt-right键按下订阅 49 {MMI::KeyEvent::KEYCODE_ALT_RIGHT, false, 0}, // alt-right键抬起订阅 50 {MMI::KeyEvent::KEYCODE_FN, true, 0}, // fn键按下订阅 51 {MMI::KeyEvent::KEYCODE_FN, false, 0}, // fn键抬起订阅 52 }; 53 enum MessageStage : uint8_t { 54 StartUp = 0, StartEnd, StartFindWidgets, FindWidgetsEnd 55 }; 56 57 inline const std::string InputEventCallback::DEFAULT_DIR = "/data/local/tmp"; 58 std::string EventData::defaultDir = InputEventCallback::DEFAULT_DIR; 59 SpecialKeyMapExistKey(int32_t keyCode,TouchOpt & touchop)60 bool SpecialKeyMapExistKey(int32_t keyCode, TouchOpt &touchop) 61 { 62 auto iter = SPECIAL_KET_MAP.find(keyCode); 63 if (iter!=SPECIAL_KET_MAP.end()) { 64 touchop = iter->second; 65 return true; 66 } 67 return false; 68 } 69 70 // KEY订阅模板函数 KeyEventSubscribeTemplate(SubscribeKeyevent & subscribeKeyevent)71 void InputEventCallback::KeyEventSubscribeTemplate(SubscribeKeyevent& subscribeKeyevent) 72 { 73 std::set<int32_t> preKeys; 74 std::shared_ptr<MMI::KeyOption> keyOption = std::make_shared<MMI::KeyOption>(); 75 keyOption->SetPreKeys(preKeys); 76 keyOption->SetFinalKey(subscribeKeyevent.keyCode); 77 keyOption->SetFinalKeyDown(subscribeKeyevent.isDown); 78 keyOption->SetFinalKeyDownDuration(KEY_DOWN_DURATION); 79 subscribeKeyevent.subId = MMI::InputManager::GetInstance()->SubscribeKeyEvent(keyOption, 80 [this](std::shared_ptr<MMI::KeyEvent> keyEvent) { 81 OnInputEvent(keyEvent); 82 }); 83 } 84 85 // key订阅 SubscribeMonitorInit()86 void InputEventCallback::SubscribeMonitorInit() 87 { 88 for (size_t i = 0; i < NEED_SUBSCRIBE_KEY.size(); i++) { 89 KeyEventSubscribeTemplate(NEED_SUBSCRIBE_KEY[i]); 90 } 91 } 92 // key取消订阅 SubscribeMonitorCancel()93 void InputEventCallback::SubscribeMonitorCancel() 94 { 95 MMI::InputManager* inputManager = MMI::InputManager::GetInstance(); 96 if (inputManager == nullptr) { 97 return; 98 } 99 for (size_t i = 0; i < NEED_SUBSCRIBE_KEY.size(); i++) { 100 if (NEED_SUBSCRIBE_KEY[i].subId >= 0) { 101 inputManager->UnsubscribeKeyEvent(NEED_SUBSCRIBE_KEY[i].subId); 102 } 103 } 104 } 105 ReadEventLine()106 void EventData::ReadEventLine() 107 { 108 std::ifstream inFile(defaultDir + "/" + "record.csv"); 109 std::string line; 110 if (inFile.is_open()) { 111 while (std::getline(inFile, line)) { 112 std::cout << line << std::endl; 113 } 114 inFile.close(); 115 } 116 } WriteLayout(nlohmann::json layout) const117 void InputEventCallback::WriteLayout(nlohmann::json layout) const 118 { 119 savePath = "/data/local/tmp/layout_" + ts + "_" + to_string(operationCount) + ".json"; 120 ofstream fout; 121 fout.open(savePath, ios::out | ios::binary); 122 if (!fout) { 123 LOG_E("Layout save to %{public}s failed: open failed!", savePath.c_str()); 124 fout.close(); 125 } else { 126 fout << layout.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); 127 fout.close(); 128 std::cout << "Layout saved to :" + savePath << std::endl; 129 LOG_I("Layout saved to : %{public}s", savePath.c_str()); 130 } 131 } 132 OnInputEventDown(std::shared_ptr<MMI::KeyEvent> keyEvent,KeyEventInfo & info) const133 void InputEventCallback::OnInputEventDown(std::shared_ptr<MMI::KeyEvent> keyEvent, KeyEventInfo &info) const 134 { 135 // 三键以上的同时按键无效 136 if (keyeventTracker_.GetInfos().size() >= KeyeventTracker::MAX_COMBINATION_SIZE) { 137 LOG_I("More than three keys are invalid at the same time"); 138 std::cout << "More than three keys are invalid at the same time" << std::endl; 139 return; 140 } 141 if (KeyeventTracker::IsCombinationKey(info.GetKeyCode())) { 142 keyeventTracker_.SetNeedRecord(true); 143 keyeventTracker_.AddDownKeyEvent(info); 144 } else { 145 keyeventTracker_.SetNeedRecord(false); 146 KeyeventTracker snapshootKeyTracker = keyeventTracker_.GetSnapshootKey(info); 147 if (recordMode.terminalCout) { 148 snapshootKeyTracker.WriteSingleData(info, cout_lock); 149 } 150 auto json = snapshootKeyTracker.WriteSingleData(info, outFile, csv_lock); 151 DoAbcCallBack(json); 152 } 153 } 154 OnInputEventUp(std::shared_ptr<MMI::KeyEvent> keyEvent,KeyEventInfo & info) const155 void InputEventCallback::OnInputEventUp(std::shared_ptr<MMI::KeyEvent> keyEvent, KeyEventInfo &info) const 156 { 157 if (recordMode.saveLayout) { 158 // 抬手时记录跳转后页面控件树 159 DumpOption option; 160 auto layout = nlohmann::json(); 161 ApiCallErr err(NO_ERROR); 162 driver.DumpUiHierarchy(layout, option, err); 163 operationCount++; 164 if (recordMode.saveLayout && err.code_ == NO_ERROR) { 165 WriteLayout(layout); 166 } else if (err.code_ != NO_ERROR) { 167 LOG_E("DumpLayout failed"); 168 } 169 } 170 if (!KeyeventTracker::IsCombinationKey(info.GetKeyCode())) { 171 KeyeventTracker snapshootKeyTracker = keyeventTracker_.GetSnapshootKey(info); 172 if (recordMode.terminalCout) { 173 snapshootKeyTracker.WriteSingleData(info, cout_lock); 174 } 175 auto json = snapshootKeyTracker.WriteSingleData(info, outFile, csv_lock, savePath); 176 DoAbcCallBack(json); 177 } 178 if (keyeventTracker_.IsNeedRecord()) { 179 keyeventTracker_.SetNeedRecord(false); 180 KeyeventTracker snapshootKeyTracker = keyeventTracker_.GetSnapshootKey(info); 181 if (recordMode.terminalCout) { 182 snapshootKeyTracker.WriteCombinationData(cout_lock); 183 } 184 auto json = snapshootKeyTracker.WriteCombinationData(outFile, csv_lock, savePath); 185 DoAbcCallBack(json); 186 } 187 keyeventTracker_.AddUpKeyEvent(info); 188 } 189 190 // KEY_ACTION OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const191 void InputEventCallback::OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const 192 { 193 if (dealSpecialKey(keyEvent)) { 194 return; 195 } 196 touchTime = GetCurrentMillisecond(); 197 auto item = keyEvent->GetKeyItem(keyEvent->GetKeyCode()); 198 if (!item) { 199 std::cout << "GetPointerItem Fail" << std::endl; 200 } 201 KeyEventInfo info; 202 info.SetActionTime(keyEvent->GetActionTime()); 203 info.SetKeyCode(keyEvent->GetKeyCode()); 204 if (keyEvent->GetKeyAction() == MMI::KeyEvent::KEY_ACTION_DOWN) { 205 OnInputEventDown(keyEvent, info); 206 } else if (keyEvent->GetKeyAction() == MMI::KeyEvent::KEY_ACTION_UP) { 207 OnInputEventUp(keyEvent, info); 208 } 209 } 210 DoAbcCallBack(nlohmann::json jsonData) const211 void InputEventCallback::DoAbcCallBack(nlohmann::json jsonData) const 212 { 213 if (abcCallBack != nullptr) { 214 auto data = nlohmann::json(); 215 data["code"] = MessageStage::FindWidgetsEnd; 216 data["data"] = jsonData; 217 abcCallBack(data); 218 } 219 } 220 dealSpecialKey(std::shared_ptr<MMI::KeyEvent> keyEvent) const221 bool InputEventCallback::dealSpecialKey(std::shared_ptr<MMI::KeyEvent> keyEvent) const 222 { 223 TouchOpt touchOpt; 224 if (SpecialKeyMapExistKey(keyEvent->GetKeyCode(), touchOpt)) { 225 if (keyEvent->GetKeyAction() == MMI::KeyEvent::KEY_ACTION_DOWN) { 226 return true; 227 } else if (keyEvent->GetKeyAction() == MMI::KeyEvent::KEY_ACTION_UP) { 228 PointerInfo& info = pointerTracker_.GetSnapshootPointerInfo(); 229 info.SetTouchOpt(touchOpt); 230 findWidgetsAllow_ = true; 231 widgetsCon.notify_all(); 232 pointerTracker_.SetLastClickInTracker(false); 233 return true; 234 } 235 } 236 return false; 237 } 238 239 // AXIS_ACTION OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const240 void InputEventCallback::OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const { 241 } 242 TimerReprintClickFunction()243 void InputEventCallback::TimerReprintClickFunction() 244 { 245 while (g_uiRecordRun) { 246 std::unique_lock <std::mutex> clickLck(g_clickMut); 247 while (!isLastClick_) { 248 clickCon.wait(clickLck); 249 } 250 std::this_thread::sleep_for( 251 std::chrono::milliseconds( 252 static_cast<int>(PointerTracker::INTERVAL_THRESHOLD * VelocityTracker::TIME_INDEX))); 253 if (isLastClick_) { 254 isLastClick_ = false; 255 pointerTracker_.SetLastClickInTracker(false); 256 findWidgetsAllow_ = true; 257 widgetsCon.notify_all(); 258 } 259 } 260 } 261 TimerTouchCheckFunction()262 void InputEventCallback::TimerTouchCheckFunction() 263 { 264 while (g_uiRecordRun) { 265 unique_lock<mutex> lock(timerMut); 266 timerCon.wait_for(lock, std::chrono::milliseconds(TIMEINTERVAL), [this] {return stopFlag;}); 267 int currentTime = GetCurrentMillisecond(); 268 int diff = currentTime - touchTime; 269 if (diff >= TIMEINTERVAL) { 270 std::cout << "No operation detected for 5 seconds, press ctrl + c to save this file?" << std::endl; 271 } 272 } 273 } 274 FindWidgetsandWriteData()275 void InputEventCallback::FindWidgetsandWriteData() 276 { 277 while (g_uiRecordRun) { 278 std::unique_lock<std::mutex> widgetsLck(widgetsMut); 279 while (!findWidgetsAllow_) { 280 widgetsCon.wait(widgetsLck); 281 } 282 if (!g_uiRecordRun) { 283 return; 284 } 285 if (abcCallBack != nullptr) { 286 auto data = nlohmann::json(); 287 data["code"] = MessageStage::StartFindWidgets; 288 abcCallBack(data); 289 } 290 std::this_thread::sleep_for(std::chrono::milliseconds(VelocityTracker::TIME_INDEX)); // 确保界面已更新 291 ApiCallErr err(NO_ERROR); 292 auto layout = nlohmann::json(); 293 DumpOption option; 294 driver.DumpUiHierarchy(layout, option, err); 295 operationCount++; 296 if (recordMode.saveLayout && err.code_ == NO_ERROR) { 297 WriteLayout(layout); 298 } else if (err.code_ != NO_ERROR) { 299 LOG_E("DumpLayout failed"); 300 } 301 selector.SetWantMulti(true); 302 driver.FindWidgets(selector, rev, err, true); 303 PointerInfo& info = pointerTracker_.GetSnapshootPointerInfo(); 304 info.SetSavePath(savePath); 305 if (recordMode.terminalCout) { 306 pointerTracker_.WriteData(info, cout_lock); // Terminal 307 } 308 auto json = pointerTracker_.WriteData(info, outFile, csv_lock); // csv 309 if (abcCallBack != nullptr) { 310 auto data = nlohmann::json(); 311 data["code"] = MessageStage::FindWidgetsEnd; 312 data["data"] = json; 313 data["layout"] = layout; 314 abcCallBack(data); 315 } 316 findWidgetsAllow_ = false; 317 widgetsCon.notify_all(); 318 } 319 } 320 WritePointerInfo() const321 void InputEventCallback::WritePointerInfo() const 322 { 323 if (pointerTracker_.IsNeedWrite()) { 324 PointerInfo info = pointerTracker_.GetSnapshootPointerInfo(); 325 if (info.GetTouchOpt() != OP_CLICK) { 326 isLastClick_ = false; 327 findWidgetsAllow_ = true; 328 widgetsCon.notify_all(); 329 } 330 if (info.GetTouchOpt() == OP_CLICK) { 331 isLastClick_ = true; 332 clickCon.notify_all(); 333 } 334 pointerTracker_.SetNeedWrite(false); 335 } 336 } 337 OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const338 void InputEventCallback::OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const 339 { 340 MMI::PointerEvent::PointerItem item; 341 bool result = pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), item); 342 if (!result) { 343 std::cout << "GetPointerItem Fail" << std::endl; 344 } 345 touchTime = GetCurrentMillisecond(); 346 TouchEventInfo touchEvent {}; 347 if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN) { 348 g_downTime = pointerEvent->GetActionTime(); 349 } 350 touchEvent.actionTime = pointerEvent->GetActionTime(); 351 touchEvent.downTime = item.GetDownTime() == 0 ? g_downTime : item.GetDownTime(); 352 touchEvent.x = item.GetDisplayX(); 353 touchEvent.y = item.GetDisplayY(); 354 touchEvent.wx = item.GetWindowX(); 355 touchEvent.wy = item.GetWindowY(); 356 std::chrono::duration<double> duration = touchEvent.GetActionTimeStamp() - touchEvent.GetDownTimeStamp(); 357 touchEvent.durationSeconds = duration.count(); 358 if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN) { 359 std::unique_lock<std::mutex> widgetsLck(widgetsMut); 360 while (findWidgetsAllow_) { 361 widgetsCon.wait(widgetsLck); 362 } 363 if (recordMode.saveWidget) { 364 touchEvent.attributes = FindWidget(driver, touchEvent.x, touchEvent.y); 365 } 366 pointerTracker_.HandleDownEvent(touchEvent); 367 } else if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_MOVE) { 368 pointerTracker_.HandleMoveEvent(touchEvent); 369 } else if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_PULL_MOVE) { 370 pointerTracker_.HandleMoveEvent(touchEvent, OP_DRAG); 371 } else if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_UP) { 372 if (recordMode.saveWidget) { 373 touchEvent.attributes = FindWidget(driver, touchEvent.x, touchEvent.y); 374 } 375 pointerTracker_.HandleUpEvent(touchEvent); 376 WritePointerInfo(); 377 } else if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_PULL_UP) { 378 if (recordMode.saveWidget) { 379 touchEvent.attributes = FindWidget(driver, touchEvent.x, touchEvent.y); 380 } 381 pointerTracker_.HandleUpEvent(touchEvent, OP_DRAG); 382 WritePointerInfo(); 383 } 384 } 385 InitReportFolder()386 bool InputEventCallback::InitReportFolder() 387 { 388 if (opendir(DEFAULT_DIR.c_str()) == nullptr) { 389 int ret = mkdir(DEFAULT_DIR.c_str(), S_IROTH | S_IRWXU | S_IRWXG); 390 if (ret != 0) { 391 std::cerr << "failed to create dir: " << DEFAULT_DIR << std::endl; 392 return false; 393 } 394 } 395 return true; 396 } 397 InitEventRecordFile()398 bool InputEventCallback::InitEventRecordFile() 399 { 400 if (!InitReportFolder()) { 401 return false; 402 } 403 filePath = DEFAULT_DIR + "/" + "record.csv"; 404 outFile.open(filePath, std::ios_base::out | std::ios_base::trunc); 405 if (!outFile) { 406 std::cerr << "Failed to create csv file at:" << filePath << std::endl; 407 return false; 408 } 409 std::cout << "The result will be written in csv file at location: " << filePath << std::endl; 410 return true; 411 } RecordInitEnv(const RecordOption & option)412 void InputEventCallback::RecordInitEnv(const RecordOption &option) 413 { 414 recordMode = option; 415 ApiCallErr err(NO_ERROR); 416 selector.SetWantMulti(true); 417 driver.FindWidgets(selector, rev, err, true); 418 auto screenSize = driver.GetDisplaySize(err); 419 Rect windowBounds = Rect(0, screenSize.px_, 0, screenSize.py_); 420 std::cout<< "windowBounds : (" << windowBounds.left_ << "," 421 << windowBounds.top_ << "," << windowBounds.right_ << "," 422 << windowBounds.bottom_ << ")" << std::endl; 423 pointerTracker_.SetWindow(windowBounds); 424 std::vector<std::string> names = GetFrontAbility(); 425 std::cout << "Current ForAbility :" << names[ZERO] << ", " << names[ONE] << std::endl; 426 if (outFile.is_open()) { 427 outFile << "windowBounds" << ','; 428 outFile << windowBounds.left_ << ','; 429 outFile << windowBounds.top_ << ','; 430 outFile << windowBounds.right_ << ','; 431 outFile << windowBounds.bottom_ << ','; 432 outFile << "0,0,0,0,,,,,,,"; 433 outFile << names[ZERO] << ','; 434 outFile << names[ONE] << ',' << std::endl; 435 } 436 } 437 UiDriverRecordStart(RecordOption modeOpt)438 int32_t UiDriverRecordStart(RecordOption modeOpt) 439 { 440 g_uiCallBackInstance = std::make_shared<InputEventCallback>(); 441 return UiDriverRecordStartTemplate(modeOpt); 442 } 443 UiDriverRecordStart(std::function<void (nlohmann::json)> handler,std::string modeOpt)444 int32_t UiDriverRecordStart(std::function<void(nlohmann::json)> handler, std::string modeOpt) 445 { 446 g_uiCallBackInstance = std::make_shared<InputEventCallback>(); 447 g_uiCallBackInstance->SetAbcCallBack(handler); 448 RecordOption opt; 449 if (modeOpt == "point") { 450 opt.saveWidget = false; 451 } 452 return UiDriverRecordStartTemplate(opt); 453 } 454 UiDriverRecordStartTemplate(RecordOption modeOpt)455 int32_t UiDriverRecordStartTemplate(RecordOption modeOpt) 456 { 457 if (g_uiCallBackInstance == nullptr) { 458 std::cout << "nullptr" << std::endl; 459 return OHOS::ERR_INVALID_VALUE; 460 } 461 auto abcCallBack = g_uiCallBackInstance->GetAbcCallBack(); 462 if (abcCallBack != nullptr) { 463 auto data = nlohmann::json(); 464 data["code"] = MessageStage::StartUp; 465 abcCallBack(data); 466 } 467 g_uiCallBackInstance->RecordInitEnv(modeOpt); 468 if (!g_uiCallBackInstance->InitEventRecordFile()) { 469 return OHOS::ERR_INVALID_VALUE; 470 } 471 // 按键订阅 472 g_uiCallBackInstance->SubscribeMonitorInit(); 473 g_callBackId = MMI::InputManager::GetInstance()->AddMonitor(g_uiCallBackInstance); 474 if (g_callBackId == -1) { 475 std::cout << "Startup Failed!" << std::endl; 476 return OHOS::ERR_INVALID_VALUE; 477 } 478 g_uiRecordRun = true; 479 ts = to_string(GetCurrentMicroseconds()); 480 // 补充click打印线程 481 std::thread clickThread(&InputEventCallback::TimerReprintClickFunction, g_uiCallBackInstance); 482 // touch计时线程 483 std::thread toughTimerThread(&InputEventCallback::TimerTouchCheckFunction, g_uiCallBackInstance); 484 // widget&data 线程 485 std::thread dataThread(&InputEventCallback::FindWidgetsandWriteData, g_uiCallBackInstance); 486 std::cout << "Started Recording Successfully..." << std::endl; 487 if (abcCallBack != nullptr) { 488 auto data = nlohmann::json(); 489 data["code"] = MessageStage::StartEnd; 490 abcCallBack(data); 491 } 492 clickThread.join(); 493 toughTimerThread.join(); 494 dataThread.join(); 495 return OHOS::ERR_OK; 496 } 497 UiDriverRecordStop()498 void UiDriverRecordStop() 499 { 500 g_uiRecordRun = false; 501 if (g_uiCallBackInstance != nullptr) { 502 g_uiCallBackInstance->isLastClick_ = true; 503 g_uiCallBackInstance->findWidgetsAllow_ = true; 504 g_uiCallBackInstance->stopFlag = true; 505 g_uiCallBackInstance->widgetsCon.notify_all(); 506 g_uiCallBackInstance->clickCon.notify_all(); 507 g_uiCallBackInstance->timerCon.notify_all(); 508 g_uiCallBackInstance->SubscribeMonitorCancel(); 509 MMI::InputManager::GetInstance()->RemoveMonitor(g_callBackId); 510 g_callBackId = -1; 511 g_uiCallBackInstance = nullptr; 512 } 513 } 514 } // namespace OHOS::uitest 515