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