• 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         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