• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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