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