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