• 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, "", ""},
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