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 16 #include "window_operator.h" 17 #include <map> 18 19 namespace OHOS::uitest { 20 using namespace std; 21 using namespace nlohmann; 22 23 enum WindowAction : uint8_t { 24 FOCUS, 25 MOVETO, 26 RESIZE, 27 SPLIT, 28 MAXIMIZE, 29 RESUME, 30 MINIMIZE, 31 CLOSE 32 }; 33 34 struct Operational { 35 WindowAction action; 36 WindowMode windowMode; 37 bool support; 38 std::string_view buttonId; 39 std::string_view message; 40 }; 41 42 static constexpr Operational OPERATIONS[] = { 43 {MOVETO, FULLSCREEN, false, "", "Fullscreen window can not move"}, 44 {MOVETO, SPLIT_PRIMARY, false, "", "SPLIT_PRIMARY window can not move"}, 45 {MOVETO, SPLIT_SECONDARY, false, "", "SPLIT_SECONDARY window can not move"}, 46 {MOVETO, FLOATING, true, "", ""}, 47 {RESIZE, FULLSCREEN, false, "", "Fullscreen window can not resize"}, 48 {RESIZE, SPLIT_PRIMARY, true, "", ""}, 49 {RESIZE, SPLIT_SECONDARY, true, "", ""}, 50 {RESIZE, FLOATING, true, "", ""}, 51 {SPLIT, FULLSCREEN, true, "container_modal_split_left_button", ""}, 52 {SPLIT, SPLIT_PRIMARY, false, "container_modal_split_left_button", "SPLIT_PRIMARY can not split again"}, 53 {SPLIT, SPLIT_SECONDARY, true, "container_modal_split_left_button", ""}, 54 {SPLIT, FLOATING, true, "container_modal_split_left_button", ""}, 55 {MAXIMIZE, FULLSCREEN, false, "container_modal_maximize_button", "Fullscreen window is already maximized"}, 56 {MAXIMIZE, SPLIT_PRIMARY, true, "container_modal_maximize_button", ""}, 57 {MAXIMIZE, SPLIT_SECONDARY, true, "container_modal_maximize_button", ""}, 58 {MAXIMIZE, FLOATING, true, "container_modal_maximize_button", ""}, 59 {RESUME, FULLSCREEN, true, "container_modal_maximize_button", ""}, 60 {RESUME, SPLIT_PRIMARY, true, "container_modal_maximize_button", ""}, 61 {RESUME, SPLIT_SECONDARY, true, "container_modal_maximize_button", ""}, 62 {RESUME, FLOATING, true, "container_modal_maximize_button", ""}, 63 {MINIMIZE, FULLSCREEN, true, "container_modal_minimize_button", ""}, 64 {MINIMIZE, SPLIT_PRIMARY, true, "container_modal_minimize_button", ""}, 65 {MINIMIZE, SPLIT_SECONDARY, true, "container_modal_minimize_button", ""}, 66 {MINIMIZE, FLOATING, true, "container_modal_minimize_button", ""}, 67 {CLOSE, FULLSCREEN, true, "container_modal_close_button", ""}, 68 {CLOSE, SPLIT_PRIMARY, true, "container_modal_close_button", ""}, 69 {CLOSE, SPLIT_SECONDARY, true, "container_modal_close_button", ""}, 70 {CLOSE, FLOATING, true, "container_modal_close_button", ""} 71 }; 72 CheckOperational(WindowAction action,WindowMode mode,ApiReplyInfo & out,string & buttonId)73 static bool CheckOperational(WindowAction action, WindowMode mode, ApiReplyInfo &out, string &buttonId) 74 { 75 for (unsigned long index = 0; index < sizeof(OPERATIONS) / sizeof(Operational); index++) { 76 if (OPERATIONS[index].action == action && OPERATIONS[index].windowMode == mode) { 77 if (OPERATIONS[index].support) { 78 buttonId = OPERATIONS[index].buttonId; 79 return true; 80 } else { 81 out.exception_ = ApiCallErr(ERR_OPERATION_UNSUPPORTED, OPERATIONS[index].message); 82 return false; 83 } 84 } 85 } 86 out.exception_ = ApiCallErr(ERR_INTERNAL, "No such window mode-action combination registered"); 87 return false; 88 } 89 WindowOperator(UiDriver & driver,const Window & window,UiOpArgs & options)90 WindowOperator::WindowOperator(UiDriver &driver, const Window &window, UiOpArgs &options) 91 : driver_(driver), window_(window), options_(options) 92 { 93 } 94 CallBar(ApiReplyInfo & out)95 void WindowOperator::CallBar(ApiReplyInfo &out) 96 { 97 Focus(out); 98 if (window_.mode_ == WindowMode::FLOATING) { 99 return; 100 } 101 auto rect = window_.bounds_; 102 static constexpr uint32_t step1 = 10; 103 static constexpr uint32_t step2 = 40; 104 Point from(rect.GetCenterX(), rect.top_ + step1); 105 Point to(rect.GetCenterX(), rect.top_ + step2); 106 auto touch = GenericSwipe(TouchOp::DRAG, from, to); 107 driver_.PerformTouch(touch, options_, out.exception_); 108 driver_.DelayMs(options_.uiSteadyThresholdMs_); 109 } 110 Focus(ApiReplyInfo & out)111 void WindowOperator::Focus(ApiReplyInfo &out) 112 { 113 if (window_.focused_) { 114 return; 115 } else { 116 auto rect = window_.visibleBounds_; 117 static constexpr uint32_t step = 10; 118 Point focus(rect.GetCenterX(), rect.top_ + step); 119 auto touch = GenericClick(TouchOp::CLICK, focus); 120 driver_.PerformTouch(touch, options_, out.exception_); 121 } 122 } 123 MoveTo(uint32_t endX,uint32_t endY,ApiReplyInfo & out)124 void WindowOperator::MoveTo(uint32_t endX, uint32_t endY, ApiReplyInfo &out) 125 { 126 Focus(out); 127 string targetBtnId; 128 if (!CheckOperational(MOVETO, window_.mode_, out, targetBtnId)) { 129 return; 130 } 131 auto rect = window_.bounds_; 132 static constexpr uint32_t step = 40; 133 Point from(rect.left_ + step, rect.top_ + step); 134 Point to(endX + step, endY + step); 135 auto touch = GenericSwipe(TouchOp::DRAG, from, to); 136 driver_.PerformTouch(touch, options_, out.exception_); 137 } 138 Resize(int32_t width,int32_t highth,ResizeDirection direction,ApiReplyInfo & out)139 void WindowOperator::Resize(int32_t width, int32_t highth, ResizeDirection direction, ApiReplyInfo &out) 140 { 141 Focus(out); 142 string targetBtnId; 143 if (!CheckOperational(RESIZE, window_.mode_, out, targetBtnId)) { 144 return; 145 } 146 Point from; 147 Point to; 148 switch (direction) { 149 case (LEFT): 150 from = Point(window_.bounds_.left_, window_.bounds_.GetCenterY()); 151 to = Point((window_.bounds_.right_ - width), window_.bounds_.GetCenterY()); 152 break; 153 case (RIGHT): 154 from = Point(window_.bounds_.right_, window_.bounds_.GetCenterY()); 155 to = Point((window_.bounds_.left_ + width), window_.bounds_.GetCenterY()); 156 break; 157 case (D_UP): 158 from = Point(window_.bounds_.GetCenterX(), window_.bounds_.top_); 159 to = Point(window_.bounds_.GetCenterX(), window_.bounds_.bottom_ - highth); 160 break; 161 case (D_DOWN): 162 from = Point(window_.bounds_.GetCenterX(), window_.bounds_.bottom_); 163 to = Point(window_.bounds_.GetCenterX(), window_.bounds_.top_ + highth); 164 break; 165 case (LEFT_UP): 166 from = Point(window_.bounds_.left_, window_.bounds_.top_); 167 to = Point(window_.bounds_.right_ - width, window_.bounds_.bottom_ - highth); 168 break; 169 case (LEFT_DOWN): 170 from = Point(window_.bounds_.left_, window_.bounds_.bottom_); 171 to = Point(window_.bounds_.right_ - width, window_.bounds_.top_ + highth); 172 break; 173 case (RIGHT_UP): 174 from = Point(window_.bounds_.right_, window_.bounds_.top_); 175 to = Point(window_.bounds_.left_ + width, window_.bounds_.bottom_ - highth); 176 break; 177 case (RIGHT_DOWN): 178 from = Point(window_.bounds_.right_, window_.bounds_.bottom_); 179 to = Point(window_.bounds_.left_ + width, window_.bounds_.top_ + highth); 180 break; 181 default: 182 break; 183 } 184 driver_.PerformTouch(GenericSwipe(TouchOp::DRAG, from, to), options_, out.exception_); 185 } 186 Split(ApiReplyInfo & out)187 void WindowOperator::Split(ApiReplyInfo &out) 188 { 189 string targetBtnId; 190 if (!CheckOperational(SPLIT, window_.mode_, out, targetBtnId)) { 191 return; 192 } 193 BarAction(targetBtnId, out); 194 if (out.exception_.code_ == ERR_OPERATION_UNSUPPORTED) { 195 out.exception_ = ApiCallErr(NO_ERROR, ""); 196 // call split bar. 197 auto selector = WidgetSelector(); 198 auto attrMatcher = WidgetMatchModel(UiAttr::KEY, "EnhanceMaximizeBtn", EQ); 199 auto windowMatcher = WidgetMatchModel(UiAttr::HOST_WINDOW_ID, to_string(window_.id_), EQ); 200 selector.AddMatcher(attrMatcher); 201 selector.AddMatcher(windowMatcher); 202 selector.AddAppLocator(window_.bundleName_); 203 selector.SetWantMulti(false); 204 vector<unique_ptr<Widget>> widgets; 205 driver_.FindWidgets(selector, widgets, out.exception_); 206 if (out.exception_.code_ != NO_ERROR) { 207 return; 208 } 209 if (widgets.empty()) { 210 out.exception_ = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "this device can not support this action"); 211 return; 212 } 213 auto rect = widgets[0]->GetBounds(); 214 Point widgetCenter(rect.GetCenterX(), rect.GetCenterY()); 215 auto touch1 = MouseMoveTo(widgetCenter); 216 driver_.PerformMouseAction(touch1, options_, out.exception_); 217 constexpr auto focusTime = 1000; 218 driver_.DelayMs(focusTime); 219 // find split btn and click. 220 auto selector2 = WidgetSelector(); 221 auto attrMatcher2 = WidgetMatchModel(UiAttr::KEY, "EnhanceMenuScreenLeftRow", EQ); 222 selector2.AddMatcher(attrMatcher2); 223 selector2.SetWantMulti(false); 224 vector<unique_ptr<Widget>> widgets2; 225 driver_.FindWidgets(selector2, widgets2, out.exception_); 226 if (widgets2.empty()) { 227 out.exception_ = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "this device can not support this action"); 228 return; 229 } 230 auto rect2 = widgets2[0]->GetBounds(); 231 Point widgetCenter2(rect2.GetCenterX(), rect2.GetCenterY()); 232 auto touch2 = GenericClick(TouchOp::CLICK, widgetCenter2); 233 driver_.PerformTouch(touch2, options_, out.exception_); 234 } 235 } 236 Maximize(ApiReplyInfo & out)237 void WindowOperator::Maximize(ApiReplyInfo &out) 238 { 239 string targetBtnId; 240 if (!CheckOperational(MAXIMIZE, window_.mode_, out, targetBtnId)) { 241 return; 242 } 243 BarAction(targetBtnId, out); 244 if (out.exception_.code_ == ERR_OPERATION_UNSUPPORTED) { 245 out.exception_ = ApiCallErr(NO_ERROR, ""); 246 BarAction("EnhanceMaximizeBtn", out); 247 } 248 } 249 Resume(ApiReplyInfo & out)250 void WindowOperator::Resume(ApiReplyInfo &out) 251 { 252 string targetBtnId; 253 if (!CheckOperational(RESUME, window_.mode_, out, targetBtnId)) { 254 return; 255 } 256 BarAction(targetBtnId, out); 257 if (out.exception_.code_ == ERR_OPERATION_UNSUPPORTED) { 258 out.exception_ = ApiCallErr(NO_ERROR, ""); 259 BarAction("EnhanceMaximizeBtn", out); 260 } 261 } 262 Minimize(ApiReplyInfo & out)263 void WindowOperator::Minimize(ApiReplyInfo &out) 264 { 265 string targetBtnId; 266 if (!CheckOperational(MINIMIZE, window_.mode_, out, targetBtnId)) { 267 return; 268 } 269 BarAction(targetBtnId, out); 270 if (out.exception_.code_ == ERR_OPERATION_UNSUPPORTED) { 271 out.exception_ = ApiCallErr(NO_ERROR, ""); 272 BarAction("EnhanceMinimizeBtn", out); 273 } 274 } 275 Close(ApiReplyInfo & out)276 void WindowOperator::Close(ApiReplyInfo &out) 277 { 278 string targetBtnId; 279 if (!CheckOperational(CLOSE, window_.mode_, out, targetBtnId)) { 280 return; 281 } 282 BarAction(targetBtnId, out); 283 if (out.exception_.code_ == ERR_OPERATION_UNSUPPORTED) { 284 out.exception_ = ApiCallErr(NO_ERROR, ""); 285 BarAction("EnhanceCloseBtn", out); 286 } 287 } 288 BarAction(string_view buttonId,ApiReplyInfo & out)289 void WindowOperator::BarAction(string_view buttonId, ApiReplyInfo &out) 290 { 291 CallBar(out); 292 auto selector = WidgetSelector(); 293 auto attrMatcher = WidgetMatchModel(UiAttr::KEY, std::string(buttonId), EQ); 294 auto windowMatcher = WidgetMatchModel(UiAttr::HOST_WINDOW_ID, to_string(window_.id_), EQ); 295 selector.AddMatcher(attrMatcher); 296 selector.AddMatcher(windowMatcher); 297 selector.AddAppLocator(window_.bundleName_); 298 selector.SetWantMulti(false); 299 vector<unique_ptr<Widget>> widgets; 300 driver_.FindWidgets(selector, widgets, out.exception_); 301 if (out.exception_.code_ != NO_ERROR) { 302 return; 303 } 304 if (widgets.empty()) { 305 out.exception_ = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "this device can not support this action"); 306 return; 307 } 308 auto rect = widgets[0]->GetBounds(); 309 Point widgetCenter(rect.GetCenterX(), rect.GetCenterY()); 310 auto touch = GenericClick(TouchOp::CLICK, widgetCenter); 311 driver_.PerformTouch(touch, options_, out.exception_); 312 } 313 } // namespace OHOS::uitest 314