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 "accessibility_touchEvent_injector.h"
17 #include "accessible_ability_manager_service.h"
18 #include "hilog_wrapper.h"
19 #include "utils.h"
20
21 namespace OHOS {
22 namespace Accessibility {
23 namespace {
24 constexpr int32_t MS_TO_US = 1000;
25 constexpr int32_t MOVE_GESTURE_MIN_PATH_COUNT = 2;
26 } // namespace
27
TouchInjectHandler(const std::shared_ptr<AppExecFwk::EventRunner> & runner,TouchEventInjector & server)28 TouchInjectHandler::TouchInjectHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner,
29 TouchEventInjector &server) : AppExecFwk::EventHandler(runner), server_(server)
30 {
31 }
32
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)33 void TouchInjectHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
34 {
35 std::shared_ptr<SendEventArgs> parameters = nullptr;
36 if (!event) {
37 HILOG_ERROR("event is nullptr");
38 return;
39 }
40 switch (event->GetInnerEventId()) {
41 case TouchEventInjector::SEND_TOUCH_EVENT_MSG:
42 parameters = event->GetSharedObject<SendEventArgs>();
43 if (parameters == nullptr) {
44 HILOG_ERROR("parameters is nullptr");
45 return;
46 }
47 if (!parameters->event_) {
48 HILOG_WARN("pointer event is nullptr");
49 return;
50 }
51 server_.SendPointerEvent(*parameters->event_);
52 break;
53 default:
54 break;
55 }
56 }
57
TouchEventInjector()58 TouchEventInjector::TouchEventInjector()
59 {
60 runner_ = Singleton<AccessibleAbilityManagerService>::GetInstance().GetMainRunner();
61 if (!runner_) {
62 HILOG_ERROR("get runner failed");
63 return;
64 }
65 handler_ = std::make_shared<TouchInjectHandler>(runner_, *this);
66 if (!handler_) {
67 HILOG_ERROR("create event handler failed");
68 return;
69 }
70 }
71
OnPointerEvent(MMI::PointerEvent & event)72 bool TouchEventInjector::OnPointerEvent(MMI::PointerEvent &event)
73 {
74 HILOG_DEBUG();
75
76 EventTransmission::OnPointerEvent(event);
77 return false;
78 }
79
DestroyEvents()80 void TouchEventInjector::DestroyEvents()
81 {
82 HILOG_DEBUG();
83 CancelInjectedEvents();
84 isDestroyEvent_ = true;
85 EventTransmission::DestroyEvents();
86 }
87
SendPointerEvent(MMI::PointerEvent & event)88 void TouchEventInjector::SendPointerEvent(MMI::PointerEvent &event)
89 {
90 HILOG_DEBUG();
91 if (GetNext() != nullptr) {
92 EventTransmission::OnPointerEvent(event);
93 if (event.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN) {
94 isGestureUnderway_ = true;
95 }
96 if (event.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_UP) {
97 isGestureUnderway_ = false;
98 }
99 }
100 }
101
CancelGesture()102 void TouchEventInjector::CancelGesture()
103 {
104 HILOG_DEBUG();
105 std::shared_ptr<MMI::PointerEvent> event;
106 MMI::PointerEvent::PointerItem pointer = {};
107 int64_t time = GetSystemTime();
108 pointer.SetDownTime(time);
109 pointer.SetPointerId(0);
110 if (GetNext() != nullptr && isGestureUnderway_) {
111 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_CANCEL, pointer, time);
112 if (event == nullptr) {
113 HILOG_ERROR("event is nullptr");
114 return;
115 }
116
117 SendPointerEvent(*event);
118 isGestureUnderway_ = false;
119 }
120 }
121
CancelInjectedEvents()122 void TouchEventInjector::CancelInjectedEvents()
123 {
124 HILOG_DEBUG();
125 if (handler_ == nullptr) {
126 HILOG_ERROR("handler_ is nullptr");
127 return;
128 }
129 if (handler_->HasInnerEvent(SEND_TOUCH_EVENT_MSG)) {
130 handler_->RemoveEvent(SEND_TOUCH_EVENT_MSG);
131 CancelGesture();
132 }
133 }
134
obtainTouchEvent(int32_t action,MMI::PointerEvent::PointerItem point,int64_t actionTime)135 std::shared_ptr<MMI::PointerEvent> TouchEventInjector::obtainTouchEvent(int32_t action,
136 MMI::PointerEvent::PointerItem point, int64_t actionTime)
137 {
138 HILOG_DEBUG();
139 std::shared_ptr<MMI::PointerEvent> pointerEvent = MMI::PointerEvent::Create();
140 if (pointerEvent == nullptr) {
141 HILOG_ERROR("pointerEvent is nullptr");
142 return nullptr;
143 }
144
145 pointerEvent->SetPointerId(point.GetPointerId());
146 pointerEvent->SetTargetDisplayId(0);
147 pointerEvent->SetPointerAction(action);
148 pointerEvent->SetActionTime(actionTime);
149 pointerEvent->SetActionStartTime(point.GetDownTime());
150 pointerEvent->AddPointerItem(point);
151 pointerEvent->SetSourceType(MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN);
152 return pointerEvent;
153 }
154
GetSystemTime()155 int64_t TouchEventInjector::GetSystemTime()
156 {
157 HILOG_DEBUG();
158
159 int64_t microsecond = Utils::GetSystemTime() * 1000;
160 return microsecond;
161 }
162
InjectEvents(const std::shared_ptr<AccessibilityGestureInjectPath> & gesturePath)163 void TouchEventInjector::InjectEvents(const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath)
164 {
165 HILOG_DEBUG();
166
167 int64_t curTime = GetSystemTime();
168 if (isDestroyEvent_ || !GetNext()) {
169 HILOG_WARN("Inject gesture fail");
170 return;
171 }
172 CancelInjectedEvents();
173 CancelGesture();
174
175 ParseTouchEventsFromGesturePath(curTime, gesturePath);
176
177 if (injectedEvents_.empty()) {
178 HILOG_WARN("No injected events");
179 return;
180 }
181 for (size_t i = 0; i < injectedEvents_.size(); i++) {
182 std::shared_ptr<SendEventArgs> parameters = std::make_shared<SendEventArgs>();
183 parameters->event_ = injectedEvents_[i];
184 if (injectedEvents_[i]) {
185 int64_t timeout = (injectedEvents_[i]->GetActionTime() - curTime) / MS_TO_US;
186 if (timeout < 0) {
187 HILOG_WARN("timeout is error.%{public}" PRId64 "", timeout);
188 } else {
189 handler_->SendEvent(SEND_TOUCH_EVENT_MSG, parameters, timeout);
190 }
191 }
192 }
193 injectedEvents_.clear();
194 }
195
ParseTapsEvents(int64_t startTime,const std::shared_ptr<AccessibilityGestureInjectPath> & gesturePath)196 void TouchEventInjector::ParseTapsEvents(int64_t startTime,
197 const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath)
198 {
199 HILOG_DEBUG();
200
201 if (!gesturePath) {
202 HILOG_ERROR("gesturePath is null.");
203 return;
204 }
205 const std::vector<AccessibilityGesturePosition> &positions = gesturePath->GetPositions();
206 size_t positionSize = positions.size();
207 if (!positionSize) {
208 HILOG_WARN("PositionSize is zero.");
209 return;
210 }
211 int64_t durationTime = gesturePath->GetDurationTime();
212 if (durationTime < 0) {
213 HILOG_WARN("DurationTime is wrong.");
214 return;
215 }
216 int64_t perDurationTime = static_cast<int64_t>(static_cast<uint64_t>(durationTime) / positionSize);
217 int64_t downTime = startTime;
218 for (size_t i = 0; i < positionSize; i++) {
219 std::shared_ptr<MMI::PointerEvent> event;
220 MMI::PointerEvent::PointerItem pointer = {};
221 pointer.SetPointerId(0);
222 // Append down event
223 int32_t px = static_cast<int32_t>(positions[i].positionX_);
224 int32_t py = static_cast<int32_t>(positions[i].positionY_);
225 pointer.SetDisplayX(px);
226 pointer.SetDisplayY(py);
227 pointer.SetDownTime(downTime);
228 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_DOWN, pointer, downTime);
229 if (event == nullptr) {
230 HILOG_ERROR("event is nullptr");
231 return;
232 }
233
234 HILOG_DEBUG("append down event");
235 injectedEvents_.push_back(event);
236
237 // Append up event
238 int64_t upTime = downTime + perDurationTime * MS_TO_US;
239 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_UP, pointer, upTime);
240 if (event == nullptr) {
241 HILOG_ERROR("event is nullptr");
242 return;
243 }
244
245 HILOG_DEBUG("append up event");
246 injectedEvents_.push_back(event);
247 downTime = upTime + DOUBLE_TAP_MIN_TIME;
248 }
249 }
250
ParseMovesEvents(int64_t startTime,const std::shared_ptr<AccessibilityGestureInjectPath> & gesturePath)251 void TouchEventInjector::ParseMovesEvents(int64_t startTime,
252 const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath)
253 {
254 HILOG_DEBUG();
255
256 if (!gesturePath) {
257 HILOG_ERROR("gesturePath is null.");
258 return;
259 }
260 std::vector<AccessibilityGesturePosition> positions = gesturePath->GetPositions();
261 size_t positionSize = positions.size();
262 if (positionSize < MOVE_GESTURE_MIN_PATH_COUNT) {
263 HILOG_WARN("PositionSize is wrong.");
264 return;
265 }
266 int64_t durationTime = gesturePath->GetDurationTime();
267 if (durationTime < 0) {
268 HILOG_WARN("DurationTime is wrong.");
269 return;
270 }
271 int64_t perDurationTime = static_cast<int64_t>(static_cast<uint64_t>(durationTime) / (positionSize - 1));
272 int64_t downTime = startTime;
273 int64_t nowTime = startTime;
274 for (size_t i = 0; i < positionSize; i++) {
275 std::shared_ptr<MMI::PointerEvent> event;
276 MMI::PointerEvent::PointerItem pointer = {};
277 int32_t px = static_cast<int32_t>(positions[i].positionX_);
278 int32_t py = static_cast<int32_t>(positions[i].positionY_);
279 pointer.SetPointerId(0);
280 pointer.SetDisplayX(px);
281 pointer.SetDisplayY(py);
282 pointer.SetDownTime(downTime);
283 if (i == 0) { // Append down event
284 HILOG_DEBUG("append down event");
285 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_DOWN, pointer, downTime);
286 if (event == nullptr) {
287 HILOG_ERROR("event is nullptr");
288 return;
289 }
290
291 injectedEvents_.push_back(event);
292 } else if (i < (positionSize - 1)) { // Append move event
293 HILOG_DEBUG("append move event");
294 nowTime += perDurationTime * MS_TO_US;
295 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_MOVE, pointer, nowTime);
296 if (event == nullptr) {
297 HILOG_ERROR("event is nullptr");
298 return;
299 }
300
301 injectedEvents_.push_back(event);
302 } else { // Append up event
303 HILOG_DEBUG("append move event");
304 nowTime += perDurationTime * MS_TO_US;
305 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_MOVE, pointer, nowTime);
306 if (event == nullptr) {
307 HILOG_ERROR("event is nullptr");
308 return;
309 }
310
311 injectedEvents_.push_back(event);
312
313 HILOG_DEBUG("append up event");
314 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_UP, pointer, nowTime);
315 if (event == nullptr) {
316 HILOG_ERROR("event is nullptr");
317 return;
318 }
319
320 injectedEvents_.push_back(event);
321 }
322 }
323 }
324
ParseTouchEventsFromGesturePath(int64_t startTime,const std::shared_ptr<AccessibilityGestureInjectPath> & gesturePath)325 void TouchEventInjector::ParseTouchEventsFromGesturePath(int64_t startTime,
326 const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath)
327 {
328 HILOG_DEBUG();
329 if (!gesturePath) {
330 HILOG_ERROR("gesturePath is null.");
331 return;
332 }
333 const std::vector<AccessibilityGesturePosition> &positions = gesturePath->GetPositions();
334 if (positions.size() == 0) {
335 HILOG_ERROR("position size is 0.");
336 return;
337 }
338 if ((positions.size() == 1) ||
339 ((positions[0].positionX_ == positions[1].positionX_) &&
340 (positions[0].positionY_ == positions[1].positionY_))) {
341 ParseTapsEvents(startTime, gesturePath);
342 } else {
343 ParseMovesEvents(startTime, gesturePath);
344 }
345 }
346 } // namespace Accessibility
347 } // namespace OHOS