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 "ui_record.h" 16 #include "ability_manager_client.h" 17 18 using namespace std; 19 using namespace std::chrono; 20 namespace OHOS::uitest { 21 enum TouchOpt : uint8_t { 22 OP_CLICK, OP_LONG_CLICK, OP_DOUBLE_CLICK, OP_SWIPE, OP_DRAG, \ 23 OP_FLING, OP_HOME, OP_RECENT, OP_RETURN 24 }; 25 std::string g_operationType[9] = { "click", "longClick", "doubleClick", "swipe", "drag", \ 26 "fling", "home", "recent", "back" }; 27 TouchOpt g_touchop = OP_CLICK; 28 VelocityTracker g_velocityTracker; 29 bool g_isClick = false; 30 int g_clickEventCount = 0; 31 constexpr int32_t NAVI_VERTI_THRE_V = 200; 32 constexpr int32_t NAVI_THRE_D = 10; 33 constexpr float MAX_THRESHOLD = 15.0; 34 constexpr float FLING_THRESHOLD = 45.0; 35 constexpr float DURATIOIN_THRESHOLD = 0.6; 36 constexpr float INTERVAL_THRESHOLD = 0.2; 37 constexpr int32_t MaxVelocity = 40000; 38 bool g_isOpDect = false; 39 std::string g_filePath; 40 std::string g_defaultDir = "/data/local/tmp/layout"; 41 std::ofstream g_outFile; 42 auto driver = UiDriver(); 43 Rect windowBounds = Rect(0, 0, 0, 0); 44 DataWrapper g_dataWrapper; 45 GetForeAbility()46 std::vector<std::string> GetForeAbility() 47 { 48 std::vector<std::string> elements; 49 auto amcPtr = AAFwk::AbilityManagerClient::GetInstance(); 50 if (amcPtr == nullptr) { 51 std::cout<<"AbilityManagerClient is nullptr"<<std::endl; 52 return elements; 53 } 54 auto elementName = amcPtr->GetTopAbility(); 55 if (elementName.GetBundleName().empty()) { 56 std::cout<<"GetTopAbility GetBundleName is nullptr"<<std::endl; 57 return elements; 58 } 59 std::string bundleName = elementName.GetBundleName(); 60 std::string abilityName = elementName.GetAbilityName(); 61 elements.push_back(bundleName); 62 elements.push_back(abilityName); 63 return elements; 64 } PrintLine(const TouchEventInfo & downEvent,const TouchEventInfo & upEvent,const std::string & actionType)65 void PrintLine(const TouchEventInfo &downEvent, const TouchEventInfo &upEvent, const std::string &actionType) 66 { 67 std::cout << "Interval: " << g_velocityTracker.GetInterVal() << std::endl; 68 std::cout << actionType << ": " ; 69 if (actionType == "fling" || actionType == "swipe" || actionType == "drag") { 70 if (downEvent.attributes.find("id")->second != "" || downEvent.attributes.find("text")->second != "") { 71 std::cout << "from Widget(id: " << downEvent.attributes.find("id")->second << ", " 72 << "type: " << downEvent.attributes.find("type")->second << ", " 73 << "text: " << downEvent.attributes.find("text")->second << ") " << std::endl; 74 } else { 75 std::cout << "from Point(x:" << downEvent.x << ", y:" << downEvent.y 76 << ") to Point(x:" << upEvent.x << ", y:" << upEvent.y << ") " << std::endl; 77 } 78 if (actionType == "fling" || actionType == "swipe") { 79 std::cout << "Off-hand speed:" << g_velocityTracker.GetMainVelocity() << ", " 80 << "Step length:" << g_velocityTracker.GetStepLength() << std::endl; 81 } 82 } else if (actionType == "click" || actionType == "longClick" || actionType == "doubleClick") { 83 std::cout << actionType << ": " ; 84 if (downEvent.attributes.find("id")->second != "" || downEvent.attributes.find("text")->second != "") { 85 std::cout << " at Widget( id: " << downEvent.attributes.find("id")->second << ", " 86 << "text: " << downEvent.attributes.find("text")->second << ", " 87 << "type: " << downEvent.attributes.find("type")->second<< ") "<< std::endl; 88 } else { 89 std::cout <<" at Point(x:" << downEvent.x << ", y:" << downEvent.y << ") "<< std::endl; 90 } 91 } else { 92 std::cout << std::endl; 93 } 94 } CommonPrintLine(TouchEventInfo & downEvent,TouchEventInfo & upEvent,const std::string & actionType)95 void CommonPrintLine(TouchEventInfo &downEvent, TouchEventInfo &upEvent, const std::string &actionType) 96 { 97 std::cout << " PointerEvent:" << g_operationType[g_touchop] 98 << " X_posi:" << g_velocityTracker.GetFirstTrackPoint().x 99 << " Y_posi:" << g_velocityTracker.GetFirstTrackPoint().y 100 << " X2_posi:" << g_velocityTracker.GetLastTrackPoint().x 101 << " Y2_posi:" << g_velocityTracker.GetLastTrackPoint().y 102 << " Interval:" << g_velocityTracker.GetInterVal() 103 << " Step:" << g_velocityTracker.GetStepLength() 104 << " Velocity:" << g_velocityTracker.GetMainVelocity() 105 << " Max_Velocity:" << MaxVelocity 106 << std::endl; 107 } WriteEventData(const VelocityTracker & velocityTracker,const std::string & actionType)108 void EventData::WriteEventData(const VelocityTracker &velocityTracker, const std::string &actionType) 109 { 110 v = velocityTracker; 111 action = actionType; 112 TouchEventInfo downEvent = v.GetFirstTrackPoint(); 113 TouchEventInfo upEvent = v.GetLastTrackPoint(); 114 if (g_recordMode == "point") { 115 CommonPrintLine(downEvent, upEvent, action); 116 } else { 117 PrintLine(downEvent, upEvent, action); 118 } 119 if (g_outFile.is_open()) { 120 g_outFile << actionType << ','; 121 g_outFile << downEvent.x << ','; 122 g_outFile << downEvent.y << ','; 123 g_outFile << upEvent.x << ','; 124 g_outFile << upEvent.y << ','; 125 g_outFile << v.GetInterVal() << ','; 126 g_outFile << v.GetStepLength() << ','; 127 g_outFile << v.GetMainVelocity() << ','; 128 g_outFile << MaxVelocity << ','; 129 if (g_recordMode == "point") { 130 g_outFile << ",,,,,,,,"; 131 } else { 132 g_outFile << downEvent.attributes.find("id")->second << ','; 133 g_outFile << downEvent.attributes.find("type")->second << ','; 134 g_outFile << downEvent.attributes.find("text")->second << ','; 135 if (actionType == "drag") { 136 g_outFile << upEvent.attributes.find("id")->second << ','; 137 g_outFile << upEvent.attributes.find("type")->second << ','; 138 g_outFile << upEvent.attributes.find("text")->second << ','; 139 } else { 140 g_outFile << ",,,"; 141 } 142 if (actionType == "click") { 143 std::vector<std::string> names = GetForeAbility(); 144 g_outFile << names[ZERO] << ','; 145 g_outFile << names[ONE] << ','; 146 } else { 147 g_outFile << ",,"; 148 } 149 } 150 g_outFile << std::endl; 151 if (g_outFile.fail()) { 152 std::cout<< " outFile failed. " <<std::endl; 153 } 154 } else { 155 std::cout << "outFile is not opened!"<< std::endl; 156 } 157 } ReadEventLine()158 void EventData::ReadEventLine() 159 { 160 std::ifstream inFile(g_defaultDir + "/" + "record.csv"); 161 enum CaseTypes : uint8_t { 162 OP_TYPE = 0, X_POSI, Y_POSI, X2_POSI, Y2_POSI, INTERVAL, LENGTH, VELO, \ 163 MAX_VEL, W_ID, W_TYPE, W_TEXT, W2_ID, W2_TYPE, W2_TEXT, BUNDLE, ABILITY 164 }; 165 char buffer[100]; 166 while (!inFile.eof()) { 167 inFile >> buffer; 168 std::string delim = ","; 169 auto caseInfo = TestUtils::split(buffer, delim); 170 if (inFile.fail()) { 171 break; 172 } else { 173 std::cout << caseInfo[OP_TYPE] << ";" 174 << std::stoi(caseInfo[X_POSI]) << ";" 175 << std::stoi(caseInfo[Y_POSI]) << ";" 176 << std::stoi(caseInfo[X2_POSI]) << ";" 177 << std::stoi(caseInfo[Y2_POSI]) << ";" 178 << std::stoi(caseInfo[INTERVAL]) << ";" 179 << std::stoi(caseInfo[LENGTH]) << ";" 180 << std::stoi(caseInfo[VELO]) << ";" 181 << std::stoi(caseInfo[MAX_VEL]) << ";" 182 << caseInfo[W_ID] << ";" 183 << caseInfo[W_TYPE] << ";" 184 << caseInfo[W_TEXT] << ";" 185 << caseInfo[W2_ID] << ";" 186 << caseInfo[W2_TYPE] << ";" 187 << caseInfo[W2_TEXT] << ";" 188 << caseInfo[BUNDLE] << ";" 189 << caseInfo[ABILITY] << ";" 190 << std::endl; 191 } 192 int gTimeIndex = 1000; 193 usleep(std::stoi(caseInfo[INTERVAL]) * gTimeIndex); 194 } 195 } SetEventData(EventData & eventData)196 void SetEventData(EventData &eventData) 197 { 198 eventData.WriteEventData(g_velocityTracker, g_operationType[g_touchop]); 199 } SaveEventData()200 void SaveEventData() 201 { 202 g_dataWrapper.ProcessData(SetEventData); 203 } OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const204 void InputEventCallback::OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const 205 { 206 if (keyEvent->GetKeyCode() == KEYCODE_BACK) { 207 g_touchop = OP_RETURN; 208 } 209 std::thread t(SaveEventData); 210 t.join(); 211 } HandleDownEvent(TouchEventInfo & event) const212 void InputEventCallback::HandleDownEvent(TouchEventInfo& event) const 213 { 214 if (g_recordMode != "point") { 215 event.attributes = FindWidget(driver, event.x, event.y).GetAttrMap(); 216 } 217 g_velocityTracker.UpdateTouchEvent(event, false); 218 } HandleMoveEvent(const TouchEventInfo & event) const219 void InputEventCallback::HandleMoveEvent(const TouchEventInfo& event) const 220 { 221 g_velocityTracker.UpdateTouchEvent(event, false); 222 if (g_velocityTracker.GetDurationTime() >= DURATIOIN_THRESHOLD && 223 g_velocityTracker.GetMoveDistance() < MAX_THRESHOLD) { 224 g_touchop = OP_LONG_CLICK; 225 g_isOpDect = true; 226 g_isClick = false; 227 } 228 } HandleUpEvent(const TouchEventInfo & event) const229 void InputEventCallback::HandleUpEvent(const TouchEventInfo& event) const 230 { 231 g_velocityTracker.UpdateTouchEvent(event, true); 232 int moveDistance = g_velocityTracker.GetMoveDistance(); 233 if (!g_isOpDect) { 234 double mainVelocity = g_velocityTracker.GetMainAxisVelocity(); 235 if (g_velocityTracker.GetDurationTime() >= DURATIOIN_THRESHOLD && 236 moveDistance < MAX_THRESHOLD) { 237 g_touchop = OP_LONG_CLICK; 238 g_isClick = false; 239 } else if (moveDistance > MAX_THRESHOLD) { 240 int startY = g_velocityTracker.GetFirstTrackPoint().y; 241 Axis maxAxis_ = g_velocityTracker.GetMaxAxis(); 242 if (fabs(mainVelocity) > FLING_THRESHOLD) { 243 g_touchop = OP_FLING; 244 g_isClick = false; 245 if ((windowBounds.bottom_ - startY <= NAVI_THRE_D) && (maxAxis_ == Axis::VERTICAL) && \ 246 (moveDistance >= NAVI_VERTI_THRE_V)) { 247 g_touchop = OP_HOME; 248 } 249 } else { 250 g_touchop = OP_SWIPE; 251 g_isClick = false; 252 if ((windowBounds.bottom_ - startY <= NAVI_THRE_D) && (maxAxis_ == Axis::VERTICAL) && \ 253 (moveDistance >= NAVI_VERTI_THRE_V)) { 254 g_touchop = OP_RECENT; 255 } 256 } 257 g_velocityTracker.UpdateStepLength(); 258 } else { 259 // up-down>=0.6s => longClick 260 if (g_isClick && g_velocityTracker.GetInterVal() < INTERVAL_THRESHOLD) { 261 // if lastOp is click && downTime-lastDownTime < 0.1 => double_click 262 g_touchop = OP_DOUBLE_CLICK; 263 g_isClick = false; 264 } else { 265 g_touchop = OP_CLICK; 266 g_isClick = true; 267 } 268 } 269 } else if (moveDistance >= MAX_THRESHOLD) { 270 g_touchop = OP_DRAG; 271 g_isClick = false; 272 } 273 if (g_touchop == OP_DRAG && g_recordMode != "point") { 274 g_velocityTracker.GetLastTrackPoint().attributes = FindWidget(driver, event.x, event.y).GetAttrMap(); 275 } 276 std::thread t(SaveEventData); 277 t.join(); 278 g_velocityTracker.Resets(); 279 g_isOpDect = false; 280 } OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const281 void InputEventCallback::OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const 282 { 283 MMI::PointerEvent::PointerItem item; 284 bool result = pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), item); 285 if (!result) { 286 std::cout << "GetPointerItem Fail" << std::endl; 287 } 288 TouchEventInfo touchEvent {}; 289 g_touchTime = GetCurrentMillisecond(); 290 TimeStamp t {std::chrono::duration_cast<TimeStamp::duration>( \ 291 std::chrono::nanoseconds(pointerEvent->GetActionTime()*1000))}; 292 touchEvent.time = t; 293 touchEvent.x = item.GetDisplayX(); 294 touchEvent.y = item.GetDisplayY(); 295 touchEvent.wx = item.GetWindowX(); 296 touchEvent.wy = item.GetWindowY(); 297 if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN) { 298 HandleDownEvent(touchEvent); 299 } else if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_MOVE) { 300 HandleMoveEvent(touchEvent); 301 } else if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_UP) { 302 HandleUpEvent(touchEvent); 303 } 304 } GetPtr()305 std::shared_ptr<InputEventCallback> InputEventCallback::GetPtr() 306 { 307 return std::make_shared<InputEventCallback>(); 308 } InitReportFolder()309 bool InitReportFolder() 310 { 311 if (opendir(g_defaultDir.c_str()) == nullptr) { 312 int ret = mkdir(g_defaultDir.c_str(), S_IROTH | S_IRWXU | S_IRWXG); 313 if (ret != 0) { 314 std::cerr << "failed to create dir: " << g_defaultDir << std::endl; 315 return false; 316 } 317 } 318 return true; 319 } InitEventRecordFile()320 bool InitEventRecordFile() 321 { 322 if (!InitReportFolder()) { 323 return false; 324 } 325 g_filePath = g_defaultDir + "/" + "record.csv"; 326 g_outFile.open(g_filePath, std::ios_base::out | std::ios_base::trunc); 327 if (!g_outFile) { 328 std::cerr << "Failed to create csv file at:" << g_filePath << std::endl; 329 return false; 330 } 331 std::cout << "The result will be written in csv file at location: " << g_filePath << std::endl; 332 return true; 333 } RecordInitEnv(const std::string & modeOpt)334 void RecordInitEnv(const std::string &modeOpt) 335 { 336 g_recordMode = modeOpt; 337 g_velocityTracker.TrackResets(); 338 ApiCallErr err(NO_ERROR); 339 auto selector = WidgetSelector(); 340 vector<std::unique_ptr<Widget>> rev; 341 driver.FindWidgets(selector, rev, err, true); 342 auto tree = driver.GetWidgetTree(); 343 windowBounds = tree->GetRootWidget()->GetBounds(); 344 std::cout<< "windowBounds : (" << windowBounds.left_ << "," 345 << windowBounds.top_ << "," << windowBounds.right_ << "," 346 << windowBounds.bottom_ << ")" << std::endl; 347 std::vector<std::string> names = GetForeAbility(); 348 std::cout << "Current ForAbility :" << names[ZERO] << ", " << names[ONE] << std::endl; 349 if (g_outFile.is_open()) { 350 g_outFile << "windowBounds" << ','; 351 g_outFile << windowBounds.left_ << ','; 352 g_outFile << windowBounds.top_ << ','; 353 g_outFile << windowBounds.right_ << ','; 354 g_outFile << windowBounds.bottom_ << ','; 355 g_outFile << "0,0,0,0,,,,,,,"; 356 g_outFile << names[ZERO] << ','; 357 g_outFile << names[ONE] << ',' << std::endl; 358 } 359 } 360 } // namespace OHOS::uitest