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 size_t index; 39 std::string_view message; 40 }; 41 42 static constexpr Operational OPERATIONS[] = { 43 {MOVETO, FULLSCREEN, false, INDEX_ZERO, "Fullscreen window can not move"}, 44 {MOVETO, SPLIT_PRIMARY, false, INDEX_ZERO, "SPLIT_PRIMARY window can not move"}, 45 {MOVETO, SPLIT_SECONDARY, false, INDEX_ZERO, "SPLIT_SECONDARY window can not move"}, 46 {MOVETO, FLOATING, true, INDEX_ZERO, ""}, 47 {RESIZE, FULLSCREEN, false, INDEX_ZERO, "Fullscreen window can not resize"}, 48 {RESIZE, SPLIT_PRIMARY, true, INDEX_ZERO, ""}, 49 {RESIZE, SPLIT_SECONDARY, true, INDEX_ZERO, ""}, 50 {RESIZE, FLOATING, true, INDEX_ZERO, ""}, 51 {SPLIT, FULLSCREEN, true, INDEX_ONE, ""}, 52 {SPLIT, SPLIT_PRIMARY, false, INDEX_ONE, "SPLIT_PRIMARY can not split again"}, 53 {SPLIT, SPLIT_SECONDARY, true, INDEX_ONE, ""}, 54 {SPLIT, FLOATING, true, INDEX_ONE, ""}, 55 {MAXIMIZE, FULLSCREEN, false, INDEX_TWO, "Fullscreen window is already maximized"}, 56 {MAXIMIZE, SPLIT_PRIMARY, true, INDEX_ONE, ""}, 57 {MAXIMIZE, SPLIT_SECONDARY, true, INDEX_TWO, ""}, 58 {MAXIMIZE, FLOATING, true, INDEX_TWO, ""}, 59 {RESUME, FULLSCREEN, true, INDEX_TWO, ""}, 60 {RESUME, SPLIT_PRIMARY, true, INDEX_ONE, ""}, 61 {RESUME, SPLIT_SECONDARY, true, INDEX_TWO, ""}, 62 {RESUME, FLOATING, true, INDEX_TWO, ""}, 63 {MINIMIZE, FULLSCREEN, true, INDEX_THREE, ""}, 64 {MINIMIZE, SPLIT_PRIMARY, true, INDEX_TWO, ""}, 65 {MINIMIZE, SPLIT_SECONDARY, true, INDEX_THREE, ""}, 66 {MINIMIZE, FLOATING, true, INDEX_THREE, ""}, 67 {CLOSE, FULLSCREEN, true, INDEX_FOUR, ""}, 68 {CLOSE, SPLIT_PRIMARY, true, INDEX_THREE, ""}, 69 {CLOSE, SPLIT_SECONDARY, true, INDEX_FOUR, ""}, 70 {CLOSE, FLOATING, true, INDEX_FOUR, ""} 71 }; 72 CheckOperational(WindowAction action,WindowMode mode,ApiReplyInfo & out,size_t & targetIndex)73 static bool CheckOperational(WindowAction action, WindowMode mode, ApiReplyInfo &out, size_t &targetIndex) 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 targetIndex = OPERATIONS[index].index; 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 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 auto touch = GenericSwipe(TouchOp::DRAG, from, to); 106 driver_.PerformTouch(touch, options_, out.exception_); 107 driver_.DelayMs(options_.uiSteadyThresholdMs_); 108 } 109 Focus(ApiReplyInfo & out)110 void WindowOperator::Focus(ApiReplyInfo &out) 111 { 112 if (window_.focused_) { 113 return; 114 } else { 115 auto rect = window_.bounds_; 116 static constexpr uint32_t step = 10; 117 Point focus(rect.GetCenterX(), rect.top_ + step); 118 auto touch = GenericClick(TouchOp::CLICK, focus); 119 driver_.PerformTouch(touch, options_, out.exception_); 120 } 121 } 122 MoveTo(uint32_t endX,uint32_t endY,ApiReplyInfo & out)123 void WindowOperator::MoveTo(uint32_t endX, uint32_t endY, ApiReplyInfo &out) 124 { 125 size_t index = 0; 126 if (!CheckOperational(MOVETO, window_.mode_, out, index)) { 127 return; 128 } 129 auto rect = window_.bounds_; 130 static constexpr uint32_t step = 40; 131 Point from(rect.left_ + step, rect.top_ + step); 132 Point to(endX + step, endY + step); 133 auto touch = GenericSwipe(TouchOp::DRAG, from, to); 134 driver_.PerformTouch(touch, options_, out.exception_); 135 } 136 Resize(int32_t width,int32_t highth,ResizeDirection direction,ApiReplyInfo & out)137 void WindowOperator::Resize(int32_t width, int32_t highth, ResizeDirection direction, ApiReplyInfo &out) 138 { 139 size_t index = 0; 140 if (!CheckOperational(RESIZE, window_.mode_, out, index)) { 141 return; 142 } 143 if ((((direction == LEFT) || (direction == RIGHT)) && highth != window_.bounds_.GetHeight()) || 144 (((direction == D_UP) || (direction == D_DOWN)) && width != window_.bounds_.GetWidth())) { 145 out.exception_ = ApiCallErr(ERR_OPERATION_UNSUPPORTED, "Resize cannot be done in this direction"); 146 return; 147 } 148 Point from; 149 Point to; 150 switch (direction) { 151 case (LEFT): 152 from = Point(window_.bounds_.left_, window_.bounds_.GetCenterY()); 153 to = Point((window_.bounds_.right_ - width), window_.bounds_.GetCenterY()); 154 break; 155 case (RIGHT): 156 from = Point(window_.bounds_.right_, window_.bounds_.GetCenterY()); 157 to = Point((window_.bounds_.left_ + width), window_.bounds_.GetCenterY()); 158 break; 159 case (D_UP): 160 from = Point(window_.bounds_.GetCenterX(), window_.bounds_.top_); 161 to = Point(window_.bounds_.GetCenterX(), window_.bounds_.bottom_ - highth); 162 break; 163 case (D_DOWN): 164 from = Point(window_.bounds_.GetCenterX(), window_.bounds_.bottom_); 165 to = Point(window_.bounds_.GetCenterX(), window_.bounds_.top_ + highth); 166 break; 167 case (LEFT_UP): 168 from = Point(window_.bounds_.left_, window_.bounds_.top_); 169 to = Point(window_.bounds_.right_ - width, window_.bounds_.bottom_ - highth); 170 break; 171 case (LEFT_DOWN): 172 from = Point(window_.bounds_.left_, window_.bounds_.bottom_); 173 to = Point(window_.bounds_.right_ - width, window_.bounds_.top_ + highth); 174 break; 175 case (RIGHT_UP): 176 from = Point(window_.bounds_.right_, window_.bounds_.top_); 177 to = Point(window_.bounds_.left_ + width, window_.bounds_.bottom_ - highth); 178 break; 179 case (RIGHT_DOWN): 180 from = Point(window_.bounds_.right_, window_.bounds_.bottom_); 181 to = Point(window_.bounds_.left_ + width, window_.bounds_.top_ + highth); 182 break; 183 default: 184 break; 185 } 186 driver_.PerformTouch(GenericSwipe(TouchOp::DRAG, from, to), options_, out.exception_); 187 } 188 Split(ApiReplyInfo & out)189 void WindowOperator::Split(ApiReplyInfo &out) 190 { 191 size_t index = 0; 192 if (!CheckOperational(SPLIT, window_.mode_, out, index)) { 193 return; 194 } 195 BarAction(index, out); 196 } 197 Maximize(ApiReplyInfo & out)198 void WindowOperator::Maximize(ApiReplyInfo &out) 199 { 200 size_t index = 0; 201 if (!CheckOperational(MAXIMIZE, window_.mode_, out, index)) { 202 return; 203 } 204 BarAction(index, out); 205 } 206 Resume(ApiReplyInfo & out)207 void WindowOperator::Resume(ApiReplyInfo &out) 208 { 209 size_t index = 0; 210 if (!CheckOperational(RESUME, window_.mode_, out, index)) { 211 return; 212 } 213 BarAction(index, out); 214 } 215 Minimize(ApiReplyInfo & out)216 void WindowOperator::Minimize(ApiReplyInfo &out) 217 { 218 size_t index = 0; 219 if (!CheckOperational(MINIMIZE, window_.mode_, out, index)) { 220 return; 221 } 222 BarAction(index, out); 223 } 224 Close(ApiReplyInfo & out)225 void WindowOperator::Close(ApiReplyInfo &out) 226 { 227 size_t index = 0; 228 if (!CheckOperational(CLOSE, window_.mode_, out, index)) { 229 return; 230 } 231 BarAction(index, out); 232 } 233 BarAction(size_t index,ApiReplyInfo & out)234 void WindowOperator::BarAction(size_t index, ApiReplyInfo &out) 235 { 236 CallBar(out); 237 auto selector = WidgetSelector(); 238 auto frontLocator = WidgetSelector(); 239 auto attrMatcher = WidgetAttrMatcher(ATTR_NAMES[UiAttr::TYPE], "Button", EQ); 240 auto windowMatcher = WidgetAttrMatcher(ATTR_NAMES[UiAttr::HOST_WINDOW_ID], to_string(window_.id_), EQ); 241 auto frontMatcher = WidgetAttrMatcher(ATTR_NAMES[UiAttr::TYPE], "DecorBar", EQ); 242 frontLocator.AddMatcher(frontMatcher); 243 selector.AddMatcher(attrMatcher); 244 selector.AddMatcher(windowMatcher); 245 selector.AddFrontLocator(frontLocator, out.exception_); 246 vector<unique_ptr<Widget>> widgets; 247 driver_.FindWidgets(selector, widgets, out.exception_); 248 if (widgets.empty()) { 249 auto selectorForJs = WidgetSelector(); 250 auto attrMatcherForJs = WidgetAttrMatcher(ATTR_NAMES[UiAttr::TYPE], "button", EQ); 251 selectorForJs.AddMatcher(attrMatcherForJs); 252 selectorForJs.AddMatcher(windowMatcher); 253 selectorForJs.AddFrontLocator(frontLocator, out.exception_); 254 driver_.FindWidgets(selectorForJs, widgets, out.exception_, false); 255 } 256 if (out.exception_.code_ != NO_ERROR) { 257 return; 258 } 259 if (widgets.size() < index) { 260 LOG_E("Not find target winAction button"); 261 return; 262 } 263 auto rect = widgets[index - 1]->GetBounds(); 264 Point widgetCenter(rect.GetCenterX(), rect.GetCenterY()); 265 auto touch = GenericClick(TouchOp::CLICK, widgetCenter); 266 driver_.PerformTouch(touch, options_, out.exception_); 267 } 268 } // namespace OHOS::uitest 269