• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 <cmath>
17 #include "ui_action.h"
18 
19 namespace OHOS::uitest {
20     using namespace std;
21     using namespace nlohmann;
22 
DecomposeClick(PointerMatrix & recv,const Point & point,const UiOpArgs & options)23     static void DecomposeClick(PointerMatrix &recv, const Point &point, const UiOpArgs &options)
24     {
25         constexpr uint32_t fingers = 1;
26         constexpr uint32_t steps = 2;
27         PointerMatrix pointer(fingers, steps);
28         pointer.PushAction(TouchEvent {ActionStage::DOWN, point, 0, options.clickHoldMs_});
29         pointer.PushAction(TouchEvent {ActionStage::UP, point, options.clickHoldMs_, 0});
30         recv = move(pointer);
31     }
32 
DecomposeLongClick(PointerMatrix & recv,const Point & point,const UiOpArgs & options)33     static void DecomposeLongClick(PointerMatrix &recv, const Point &point, const UiOpArgs &options)
34     {
35         // should sleep after touch-down to make long-click duration
36         constexpr uint32_t fingers = 1;
37         constexpr uint32_t steps = 2;
38         PointerMatrix pointer(fingers, steps);
39         pointer.PushAction(TouchEvent {ActionStage::DOWN, point, 0, options.longClickHoldMs_});
40         pointer.PushAction(TouchEvent {ActionStage::UP, point, options.longClickHoldMs_, 0});
41         recv = move(pointer);
42     }
43 
DecomposeDoubleClick(PointerMatrix & recv,const Point & point,const UiOpArgs & options)44     static void DecomposeDoubleClick(PointerMatrix &recv, const Point &point, const UiOpArgs &options)
45     {
46         const auto msInterval = options.doubleClickIntervalMs_;
47         constexpr uint32_t fingers = 1;
48         constexpr uint32_t steps = 4;
49         PointerMatrix pointer(fingers, steps);
50         pointer.PushAction(TouchEvent {ActionStage::DOWN, point, 0, options.clickHoldMs_});
51         pointer.PushAction(TouchEvent {ActionStage::UP, point, options.clickHoldMs_, msInterval});
52 
53         pointer.PushAction(TouchEvent {ActionStage::DOWN, point, 0, options.clickHoldMs_});
54         pointer.PushAction(TouchEvent {ActionStage::UP, point, options.clickHoldMs_, 0});
55         recv = move(pointer);
56     }
57 
DecomposeComputeSwipe(PointerMatrix & recv,const Point & from,const Point & to,bool drag,const UiOpArgs & options)58     static void DecomposeComputeSwipe(PointerMatrix &recv, const Point &from, const Point &to, bool drag,
59                                       const UiOpArgs &options)
60     {
61         const int32_t distanceX = to.px_ - from.px_;
62         const int32_t distanceY = to.py_ - from.py_;
63         const uint32_t distance = sqrt(distanceX * distanceX + distanceY * distanceY);
64         const uint32_t timeCostMs = (distance * 1000) / options.swipeVelocityPps_;
65         if (distance < 1) {
66             // do not need to execute swipe
67             return;
68         }
69         const auto steps = options.swipeStepsCounts_;
70         const uint32_t intervalMs = timeCostMs / steps + 1;
71         constexpr uint32_t fingers = 1;
72         PointerMatrix pointer(fingers, steps + 1);
73 
74         pointer.PushAction(TouchEvent {ActionStage::DOWN, {from.px_, from.py_}, 0, intervalMs});
75         for (uint16_t step = 1; step < steps; step++) {
76             const int32_t pointX = from.px_ + (distanceX * step) / steps;
77             const int32_t pointY = from.py_ + (distanceY * step) / steps;
78             const uint32_t timeOffsetMs = (timeCostMs * step) / steps;
79             pointer.PushAction(TouchEvent {ActionStage::MOVE, {pointX, pointY}, timeOffsetMs, intervalMs});
80         }
81 
82         pointer.PushAction(TouchEvent {ActionStage::UP, {to.px_, to.py_}, timeCostMs, intervalMs});
83         if (drag) {
84             // drag needs longPressDown firstly
85             pointer.At(fingers - 1, 0).holdMs_ += options.longClickHoldMs_;
86             for (uint32_t idx = 1; idx < pointer.GetSize(); idx++) {
87                 pointer.At(fingers - 1, idx).downTimeOffsetMs_ += options.longClickHoldMs_;
88             }
89         }
90         recv = move(pointer);
91     }
92 
Decompose(PointerMatrix & recv,const UiOpArgs & options) const93     void GenericClick::Decompose(PointerMatrix &recv, const UiOpArgs &options) const
94     {
95         DCHECK(type_ >= TouchOp::CLICK && type_ <= TouchOp::DOUBLE_CLICK_P);
96         switch (type_) {
97             case CLICK:
98                 DecomposeClick(recv, point_, options);
99                 break;
100             case LONG_CLICK:
101                 DecomposeLongClick(recv, point_, options);
102                 break;
103             case DOUBLE_CLICK_P:
104                 DecomposeDoubleClick(recv, point_, options);
105                 break;
106             default:
107                 break;
108         }
109         for (uint32_t index = 0; index < recv.GetSize(); index++) {
110             recv.At(recv.GetFingers() - 1, index).flags_ = type_;
111         }
112     }
113 
Decompose(PointerMatrix & recv,const UiOpArgs & options) const114     void GenericSwipe::Decompose(PointerMatrix &recv, const UiOpArgs &options) const
115     {
116         DCHECK(type_ >= TouchOp::SWIPE && type_ <= TouchOp::DRAG);
117         DecomposeComputeSwipe(recv, from_, to_, type_ == TouchOp::DRAG, options);
118         for (uint32_t index = 0; index < recv.GetSize(); index++) {
119             recv.At(recv.GetFingers() - 1, index).flags_ = type_;
120         }
121     }
122 
Decompose(PointerMatrix & recv,const UiOpArgs & options) const123     void GenericPinch::Decompose(PointerMatrix &recv, const UiOpArgs &options) const
124     {
125         const int32_t distanceX0 = abs(rect_.GetCenterX() - rect_.left_) * abs(scale_ - 1);
126         PointerMatrix pointer1;
127         PointerMatrix pointer2;
128         if (scale_ > 1) {
129             auto fromPoint0 = Point(rect_.GetCenterX() - options.pinchWidgetDeadZone_, rect_.GetCenterY());
130             auto toPoint0 = Point((rect_.GetCenterX() - distanceX0), rect_.GetCenterY());
131             auto fromPoint1 = Point(rect_.GetCenterX() + options.pinchWidgetDeadZone_, rect_.GetCenterY());
132             auto toPoint1 = Point((rect_.GetCenterX() + distanceX0), rect_.GetCenterY());
133             DecomposeComputeSwipe(pointer1, fromPoint0, toPoint0, false, options);
134             DecomposeComputeSwipe(pointer2, fromPoint1, toPoint1, false, options);
135         } else if (scale_ < 1) {
136             auto fromPoint0 = Point(rect_.left_ + options.pinchWidgetDeadZone_, rect_.GetCenterY());
137             auto toPoint0 = Point((rect_.left_ + distanceX0), rect_.GetCenterY());
138             auto fromPoint1 = Point(rect_.right_ - options.pinchWidgetDeadZone_, rect_.GetCenterY());
139             auto toPoint1 = Point((rect_.right_ - distanceX0), rect_.GetCenterY());
140             DecomposeComputeSwipe(pointer1, fromPoint0, toPoint0, false, options);
141             DecomposeComputeSwipe(pointer2, fromPoint1, toPoint1, false, options);
142         }
143 
144         PointerMatrix pointer3(pointer1.GetFingers() + pointer2.GetFingers(), pointer1.GetSteps());
145         for (uint32_t index = 0; index < pointer1.GetSize(); index++) {
146             pointer3.PushAction(pointer1.At(0, index));
147         }
148         for (uint32_t index = 0; index < pointer2.GetSize(); index++) {
149             pointer3.PushAction(pointer2.At(0, index));
150         }
151         recv = move(pointer3);
152     }
153 
Decompose(PointerMatrix & recv,const UiOpArgs & options) const154     void MultiPointerAction::Decompose(PointerMatrix &recv, const UiOpArgs &options) const
155     {
156         PointerMatrix matrix(pointers_.GetFingers(), pointers_.GetSteps() + 1);
157         constexpr int32_t flag = 0x10000; // set the low 16 bits of data as coordinates.
158         for (uint32_t finger = 0; finger < pointers_.GetFingers(); finger++) {
159             uint32_t timeOffsetMs = 0;
160             uint32_t intervalMs = 0;
161             constexpr uint32_t unitConversionConstant = 1000;
162             for (uint32_t step = 0; step < pointers_.GetSteps() - 1; step++) {
163                 const int32_t pxTo = (pointers_.At(finger, step + 1).point_.px_) % flag;
164                 const int32_t pxFrom = (pointers_.At(finger, step).point_.px_) % flag;
165                 const int32_t distanceX = pxTo - pxFrom;
166                 const int32_t pyTo = pointers_.At(finger, step + 1).point_.py_;
167                 const int32_t pyFrom = pointers_.At(finger, step).point_.py_;
168                 const int32_t distanceY = pyTo - pyFrom;
169                 auto stayMs = (pointers_.At(finger, step).point_.px_) / flag;
170                 const uint32_t distance = sqrt(distanceX * distanceX + distanceY * distanceY);
171                 intervalMs = (distance * unitConversionConstant) / options.swipeVelocityPps_;
172                 auto holdMs = (stayMs == 0) ? intervalMs : stayMs;
173                 if (step == 0) {
174                     matrix.PushAction(TouchEvent {ActionStage::DOWN, {pxFrom, pyFrom}, 0, holdMs});
175                 } else {
176                     timeOffsetMs += intervalMs;
177                     matrix.PushAction(TouchEvent {ActionStage::MOVE, {pxFrom, pyFrom}, timeOffsetMs, holdMs});
178                 }
179             }
180             auto endPx = (pointers_.At(finger, pointers_.GetSteps() - 1).point_.px_) % flag;
181             auto endPy = pointers_.At(finger, pointers_.GetSteps() - 1).point_.py_;
182             auto endTime = (pointers_.At(finger, pointers_.GetSteps() - 1).point_.px_) / flag;
183             auto endStayTime = (endTime == 0) ? intervalMs : endTime;
184             matrix.PushAction(TouchEvent {ActionStage::MOVE, {endPx, endPy}, timeOffsetMs, endStayTime});
185             matrix.PushAction(TouchEvent {ActionStage::UP, {endPx, endPy}, timeOffsetMs, intervalMs});
186         }
187         recv = move(matrix);
188     }
189 
PointerMatrix()190     PointerMatrix::PointerMatrix() {};
191 
PointerMatrix(uint32_t fingersNum,uint32_t stepsNum)192     PointerMatrix::PointerMatrix(uint32_t fingersNum, uint32_t stepsNum)
193     {
194         this->fingerNum_ = fingersNum;
195         this->stepNum_ = stepsNum;
196         this->capacity_ = this->fingerNum_ * this->stepNum_;
197         this->size_ = 0;
198         this->data_ = std::make_unique<TouchEvent[]>(this->capacity_);
199     }
200 
operator =(PointerMatrix && other)201     PointerMatrix& PointerMatrix::operator=(PointerMatrix&& other)
202     {
203         this->data_ = move(other.data_);
204         this->fingerNum_ = other.fingerNum_;
205         this->stepNum_ = other.stepNum_;
206         this->capacity_ = other.capacity_;
207         this->size_ = other.size_;
208         other.fingerNum_ = 0;
209         other.stepNum_ = 0;
210         other.capacity_ = 0;
211         other.size_ = 0;
212         return *this;
213     }
214 
~PointerMatrix()215     PointerMatrix::~PointerMatrix() {}
216 
PushAction(const TouchEvent & ptr)217     void PointerMatrix::PushAction(const TouchEvent& ptr)
218     {
219         if (this->capacity_ == this->size_) {
220             return;
221         }
222         *(this->data_.get() + this->size_) = ptr;
223         this->size_++;
224     }
225 
Empty() const226     bool PointerMatrix::Empty() const
227     {
228         if (this->size_ == 0) {
229             return true;
230         }
231         return false;
232     }
233 
At(uint32_t fingerIndex,uint32_t stepIndex) const234     TouchEvent& PointerMatrix::At(uint32_t fingerIndex, uint32_t stepIndex) const
235     {
236         return *(this->data_.get() + (fingerIndex * this->stepNum_ + stepIndex));
237     }
238 
GetCapacity() const239     uint32_t PointerMatrix::GetCapacity() const
240     {
241         return this->capacity_;
242     }
243 
GetSize() const244     uint32_t PointerMatrix::GetSize() const
245     {
246         return this->size_;
247     }
248 
GetSteps() const249     uint32_t PointerMatrix::GetSteps() const
250     {
251         return this->stepNum_;
252     }
253 
GetFingers() const254     uint32_t PointerMatrix::GetFingers() const
255     {
256         return this->fingerNum_;
257     }
258 
ConvertToMouseEvents(vector<MouseEvent> & recv) const259     void PointerMatrix::ConvertToMouseEvents(vector<MouseEvent> &recv) const
260     {
261         for (auto finger = 0; finger < fingerNum_; finger++) {
262             for (auto step = 0; step < stepNum_; step++) {
263                 auto touchEvent = At(finger, step);
264                 recv.push_back(MouseEvent {touchEvent.stage_, touchEvent.point_, MouseButton::BUTTON_LEFT, {},
265                                            touchEvent.holdMs_});
266             }
267         }
268     }
269 
Decompose(std::vector<MouseEvent> & recv,const UiOpArgs & opt) const270     void MouseMoveTo::Decompose(std::vector<MouseEvent> &recv, const UiOpArgs &opt) const
271     {
272         recv.push_back(MouseEvent {ActionStage::MOVE, point_, MouseButton::BUTTON_NONE, {}, 0});
273     }
274 
Decompose(std::vector<MouseEvent> & recv,const UiOpArgs & opt) const275     void MouseSwipe::Decompose(std::vector<MouseEvent> &recv, const UiOpArgs &opt) const
276     {
277         DCHECK(type_ >= TouchOp::SWIPE && type_ <= TouchOp::DRAG);
278         PointerMatrix touchEvents;
279         DecomposeComputeSwipe(touchEvents, from_, to_, type_ == TouchOp::DRAG, opt);
280         touchEvents.ConvertToMouseEvents(recv);
281         if (type_ == TouchOp::SWIPE) {
282             recv.front().stage_ = ActionStage::MOVE;
283             recv.back().stage_ = ActionStage::MOVE;
284         }
285     }
286 
Decompose(std::vector<MouseEvent> & recv,const UiOpArgs & opt) const287     void MouseClick::Decompose(std::vector<MouseEvent> &recv, const UiOpArgs &opt) const
288     {
289         DCHECK(type_ >= TouchOp::CLICK && type_ <= TouchOp::DOUBLE_CLICK_P);
290         PointerMatrix touchEvents;
291         switch (type_) {
292             case CLICK:
293                 DecomposeClick(touchEvents, point_, opt);
294                 break;
295             case LONG_CLICK:
296                 DecomposeLongClick(touchEvents, point_, opt);
297                 break;
298             case DOUBLE_CLICK_P:
299                 DecomposeDoubleClick(touchEvents, point_, opt);
300                 break;
301             default:
302                 break;
303         }
304         touchEvents.ConvertToMouseEvents(recv);
305         for (auto index = 0; index < recv.size(); index++) {
306             recv[index].button_ = button_;
307         }
308         vector<KeyEvent> keyAction1;
309         keyAction1.push_back(KeyEvent {ActionStage::DOWN, key1_, opt.keyHoldMs_});
310         keyAction1.push_back(KeyEvent {ActionStage::DOWN, key2_, opt.keyHoldMs_});
311         auto keyDown = MouseEvent {ActionStage::MOVE, point_, MouseButton::BUTTON_NONE, keyAction1, opt.clickHoldMs_};
312         recv.insert(recv.begin(), keyDown);
313 
314         vector<KeyEvent> keyAction2;
315         keyAction2.push_back(KeyEvent {ActionStage::UP, key2_, opt.keyHoldMs_});
316         keyAction2.push_back(KeyEvent {ActionStage::UP, key1_, opt.keyHoldMs_});
317         auto keyUp = MouseEvent {ActionStage::UP, point_, MouseButton::BUTTON_NONE, keyAction2, 0};
318         recv.push_back(keyUp);
319     }
320 
Decompose(std::vector<MouseEvent> & recv,const UiOpArgs & opt) const321     void MouseScroll::Decompose(std::vector<MouseEvent> &recv, const UiOpArgs &opt) const
322     {
323         recv.push_back(MouseEvent {ActionStage::MOVE, point_, MouseButton::BUTTON_NONE, {}, 0});
324         constexpr int32_t thousandMilliseconds = 1000;
325         auto focusTimeMs = thousandMilliseconds / speed_ / 2;
326         auto stage  = (scrollValue_ > 0) ? AXIS_DOWN : AXIS_UP;
327         vector<KeyEvent> keyAction1;
328         keyAction1.push_back(KeyEvent {ActionStage::DOWN, key1_, opt.keyHoldMs_});
329         keyAction1.push_back(KeyEvent {ActionStage::DOWN, key2_, opt.keyHoldMs_});
330         recv.push_back(MouseEvent {stage, point_, MouseButton::BUTTON_NONE, keyAction1, focusTimeMs});
331         recv.push_back(MouseEvent {ActionStage::AXIS_STOP, point_, MouseButton::BUTTON_NONE, {}, focusTimeMs});
332 
333         auto steps = abs(scrollValue_);
334         for (auto index = 1; index < steps - 1; index++) {
335             recv.push_back(MouseEvent {stage, point_, MouseButton::BUTTON_NONE, {}, focusTimeMs});
336             recv.push_back(MouseEvent {ActionStage::AXIS_STOP, point_, MouseButton::BUTTON_NONE, {}, focusTimeMs});
337         }
338 
339         vector<KeyEvent> keyAction2;
340         keyAction2.push_back(KeyEvent {ActionStage::UP, key2_, opt.keyHoldMs_});
341         keyAction2.push_back(KeyEvent {ActionStage::UP, key1_, opt.keyHoldMs_});
342         if (steps > 1) {
343             recv.push_back(MouseEvent {stage, point_, MouseButton::BUTTON_NONE, {}, focusTimeMs});
344             recv.push_back(MouseEvent {ActionStage::AXIS_STOP, point_, MouseButton::BUTTON_NONE, keyAction2,
345                                        focusTimeMs});
346         } else {
347             recv.push_back(MouseEvent {ActionStage::NONE, point_, MouseButton::BUTTON_NONE, keyAction2, focusTimeMs});
348         }
349     }
350 
Decompose(PointerMatrix & recv,const UiOpArgs & options) const351     void GenericAtomicAction::Decompose(PointerMatrix &recv, const UiOpArgs &options) const
352     {
353         DCHECK(stage_ >= ActionStage::DOWN && stage_ <= ActionStage::UP);
354         constexpr uint32_t fingers = 1;
355         constexpr uint32_t steps = 1;
356         PointerMatrix pointer(fingers, steps);
357         pointer.PushAction(TouchEvent {stage_, point_, 0, 0, 0});
358         recv = move(pointer);
359     }
360 }
361