1 /*
2 * Copyright (c) 2024 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 #include "long_press_subscriber_handler.h"
16
17 #include "app_mgr_client.h"
18 #include "key_command_handler_util.h"
19
20 #undef MMI_LOG_DOMAIN
21 #define MMI_LOG_DOMAIN MMI_LOG_HANDLER
22 #undef MMI_LOG_TAG
23 #define MMI_LOG_TAG "LongPressSubscriberHandler"
24
25 namespace OHOS {
26 namespace MMI {
27 namespace {
28 constexpr int32_t ONE_FINGER { 1 };
29 constexpr int32_t TWO_FINGER { 2 };
30 constexpr int32_t DEFAULT_USER_ID { 100 };
31 constexpr int32_t PX_BASE { 160 };
32 constexpr int32_t MS_TO_US { 1000 };
33
34 }
Compare(const std::shared_ptr<Subscriber> & a,const std::shared_ptr<Subscriber> & b)35 bool Compare(const std::shared_ptr<Subscriber> &a, const std::shared_ptr<Subscriber> &b)
36 {
37 return a->duration_ < b->duration_;
38 }
39
LongPressSubscriberHandler()40 LongPressSubscriberHandler::LongPressSubscriberHandler() {}
41
~LongPressSubscriberHandler()42 LongPressSubscriberHandler::~LongPressSubscriberHandler() {}
43
SubscribeLongPressEvent(SessionPtr sess,int32_t subscribeId,const LongPressRequest & longPressRequest)44 int32_t LongPressSubscriberHandler::SubscribeLongPressEvent(SessionPtr sess, int32_t subscribeId,
45 const LongPressRequest &longPressRequest)
46 {
47 CALL_DEBUG_ENTER;
48 CHKPR(sess, ERROR_NULL_POINTER);
49 MMI_HILOGD("SubscribeId:%{public}d, fingerCount:%{public}d, duration:%{public}d",
50 subscribeId, longPressRequest.fingerCount, longPressRequest.duration);
51 if (subscribeId < 0) {
52 MMI_HILOGE("Invalid subscribeId");
53 return RET_ERR;
54 }
55
56 AddDurationTimer(longPressRequest.duration);
57 auto subscriber = std::make_shared<Subscriber>(subscribeId, sess, longPressRequest.fingerCount,
58 longPressRequest.duration);
59
60 AddSessSubscriber(subscriber);
61 InsertSubScriber(std::move(subscriber));
62 InitSessionDeleteCallback();
63 return RET_OK;
64 }
65
UnsubscribeLongPressEvent(SessionPtr sess,int32_t subscribeId)66 int32_t LongPressSubscriberHandler::UnsubscribeLongPressEvent(SessionPtr sess, int32_t subscribeId)
67 {
68 CALL_INFO_TRACE;
69 CHKPR(sess, ERROR_NULL_POINTER);
70 if (subscribeId < 0) {
71 MMI_HILOGE("Invalid subscribeId:%{public}d", subscribeId);
72 return RET_ERR;
73 }
74
75 for (auto it = subscriberInfos_.begin(); it != subscriberInfos_.end(); ++it) {
76 std::vector<std::shared_ptr<Subscriber>> &subscribers = it->second;
77 for (auto iter = subscribers.begin(); iter != subscribers.end(); ++iter) {
78 if ((*iter)->sess_ == sess && (*iter)->id_ == subscribeId) {
79 subscribers.erase(iter);
80 auto fingerCount = it->first.first;
81 auto duration = it->first.second;
82 if (subscribers.empty()) {
83 subscriberInfos_.erase(it);
84 }
85 RemoveDurationTimer(fingerCount, duration);
86 RemoveSessSubscriber(sess, subscribeId);
87 MMI_HILOGD("UnsubscribeLongPressEvent successed with %{public}d", subscribeId);
88 return RET_OK;
89 }
90 }
91 }
92 MMI_HILOGE("UnsubscribeLongPressEvent failed with %{public}d", subscribeId);
93 return RET_ERR;
94 }
95
AddDurationTimer(int32_t duration)96 void LongPressSubscriberHandler::AddDurationTimer(int32_t duration)
97 {
98 CALL_DEBUG_ENTER;
99 bool isExist = false;
100 for (auto &durationTimer : durationTimers_) {
101 if (durationTimer.duration == duration) {
102 isExist = true;
103 break;
104 }
105 }
106 if (!isExist) {
107 DurationTimer durationTimer = {
108 .duration = duration,
109 };
110 durationTimers_.push_back(durationTimer);
111 }
112 }
113
RemoveDurationTimer(int32_t fingerCount,int32_t duration)114 void LongPressSubscriberHandler::RemoveDurationTimer(int32_t fingerCount, int32_t duration)
115 {
116 CALL_DEBUG_ENTER;
117 for (auto it = subscriberInfos_.begin(); it != subscriberInfos_.end(); ++it) {
118 if (it->first.second == duration && !it->second.empty()) {
119 return;
120 }
121 }
122 for (auto timer = durationTimers_.begin(); timer != durationTimers_.end(); ++timer) {
123 if (timer->duration == duration) {
124 durationTimers_.erase(timer);
125 return;
126 }
127 }
128 }
129
AddSessSubscriber(const std::shared_ptr<Subscriber> subscriber)130 void LongPressSubscriberHandler::AddSessSubscriber(const std::shared_ptr<Subscriber> subscriber)
131 {
132 CALL_DEBUG_ENTER;
133 CHKPV(subscriber);
134 std::vector<std::shared_ptr<Subscriber>> &subscribers = sessManager_[subscriber->sess_];
135 subscribers.insert(std::lower_bound(subscribers.begin(), subscribers.end(), subscriber, Compare), subscriber);
136 }
137
RemoveSessSubscriber(SessionPtr sess,int32_t subscribeId)138 void LongPressSubscriberHandler::RemoveSessSubscriber(SessionPtr sess, int32_t subscribeId)
139 {
140 CALL_DEBUG_ENTER;
141 CHKPV(sess);
142 auto it = sessManager_.find(sess);
143 if (it == sessManager_.end()) {
144 MMI_HILOGE("Not found the sess");
145 return;
146 }
147 std::vector<std::shared_ptr<Subscriber>> &subscribers = it->second;
148 for (auto iter = subscribers.begin(); iter != subscribers.end(); ++iter) {
149 if ((*iter)->id_ == subscribeId) {
150 subscribers.erase(iter);
151 if (subscribers.empty()) {
152 sessManager_.erase(it);
153 }
154 return;
155 }
156 }
157 }
158
OnSubscribeLongPressEvent(int32_t fingerCount,int32_t duration)159 void LongPressSubscriberHandler::OnSubscribeLongPressEvent(int32_t fingerCount, int32_t duration)
160 {
161 CALL_DEBUG_ENTER;
162 MMI_HILOGD("FingerCount:%{public}d, duration:%{public}d", fingerCount, duration);
163 auto pair = std::make_pair(fingerCount, duration);
164 auto it = subscriberInfos_.find(pair);
165 if (subscriberInfos_.find(pair) == subscriberInfos_.end()) {
166 MMI_HILOGE("Not found the subscriber, fingerCount:%{public}d, duration:%{public}d",
167 fingerCount, duration);
168 return;
169 }
170 std::vector<std::shared_ptr<Subscriber>> &subscribers = it->second;
171 for (const auto &subscriber : subscribers) {
172 NotifySubscriber(subscriber, RET_OK);
173 }
174 }
175
InsertSubScriber(const std::shared_ptr<Subscriber> subscriber)176 void LongPressSubscriberHandler::InsertSubScriber(const std::shared_ptr<Subscriber> subscriber)
177 {
178 CALL_DEBUG_ENTER;
179 CHKPV(subscriber);
180 auto pair = std::make_pair(subscriber->fingerCount_, subscriber->duration_);
181 auto it = subscriberInfos_.find(pair);
182 if (it != subscriberInfos_.end()) {
183 std::vector<std::shared_ptr<Subscriber>> &subscribers = it->second;
184 for (const auto &sub : subscribers) {
185 if (subscriber->sess_ != nullptr && sub->id_ == subscriber->id_ && sub->sess_ == subscriber->sess_) {
186 MMI_HILOGW("Repeat registration id:%{public}d, desc:%{public}s",
187 subscriber->id_, subscriber->sess_->GetDescript().c_str());
188 return;
189 }
190 }
191 }
192 subscriberInfos_[pair].push_back(subscriber);
193 }
194
OnSessionDelete(SessionPtr sess)195 void LongPressSubscriberHandler::OnSessionDelete(SessionPtr sess)
196 {
197 CALL_DEBUG_ENTER;
198 CHKPV(sess);
199 for (auto it = subscriberInfos_.begin(); it != subscriberInfos_.end();) {
200 std::vector<std::shared_ptr<Subscriber>> &subscribers = it->second;
201 for (auto iter = subscribers.begin(); iter != subscribers.end();) {
202 if ((*iter)->sess_ == sess) {
203 RemoveSessSubscriber(sess, (*iter)->id_);
204 iter = subscribers.erase(iter);
205 auto fingerCount = it->first.first;
206 auto duration = it->first.second;
207 RemoveDurationTimer(fingerCount, duration);
208 continue;
209 }
210 ++iter;
211 }
212 if (subscribers.empty()) {
213 it = subscriberInfos_.erase(it);
214 } else {
215 ++it;
216 }
217 }
218 }
219
HandleFingerGestureDownEvent(const std::shared_ptr<PointerEvent> touchEvent)220 void LongPressSubscriberHandler::HandleFingerGestureDownEvent(const std::shared_ptr<PointerEvent> touchEvent)
221 {
222 CALL_DEBUG_ENTER;
223 CHKPV(touchEvent);
224 auto fingerCount = touchEvent->GetPointerIds().size();
225 if (fingerCount > 0 && fingerCount <= TwoFingerGesture::MAX_TOUCH_NUM) {
226 touchEvent_ = touchEvent;
227 int32_t id = touchEvent->GetPointerId();
228 PointerEvent::PointerItem item;
229 touchEvent->GetPointerItem(id, item);
230 fingerGesture_.touches[fingerCount - 1].id = id;
231 fingerGesture_.touches[fingerCount - 1].x = item.GetDisplayX();
232 fingerGesture_.touches[fingerCount - 1].y = item.GetDisplayY();
233 fingerGesture_.touches[fingerCount - 1].downTime = item.GetDownTime();
234 } else {
235 MMI_HILOGD("The number of finger count is not 1 or 2");
236 return;
237 }
238 if (fingerCount == static_cast<size_t>(ONE_FINGER)) {
239 StartFingerGesture(ONE_FINGER);
240 } else if (fingerCount == static_cast<size_t>(TWO_FINGER)) {
241 StopFingerGesture();
242 auto firstFinger = fingerGesture_.touches[0];
243 auto secondFinger = fingerGesture_.touches[1];
244 auto pressTimeInterval = fabs(firstFinger.downTime - secondFinger.downTime);
245 if (pressTimeInterval > TWO_FINGERS_TIME_LIMIT) {
246 MMI_HILOGI("Two fingers time too long firstdownTime:%{public}" PRId64 ",seconddownTime:%{public}" PRId64,
247 firstFinger.downTime, secondFinger.downTime);
248 return;
249 }
250 StartFingerGesture(TWO_FINGER);
251 } else {
252 MMI_HILOGW("The number of finger count is not 1 or 2");
253 StopFingerGesture();
254 }
255 }
256
HandleFingerGestureMoveEvent(const std::shared_ptr<PointerEvent> touchEvent)257 void LongPressSubscriberHandler::HandleFingerGestureMoveEvent(const std::shared_ptr<PointerEvent> touchEvent)
258 {
259 CALL_DEBUG_ENTER;
260 CHKPV(touchEvent);
261 if (isAllTimerClosed) {
262 MMI_HILOGD("Finger gesture has stopped");
263 return;
264 }
265 auto fingerCount = touchEvent->GetPointerIds().size();
266 if (fingerCount > static_cast<size_t>(TWO_FINGER)) {
267 MMI_HILOGE("Not support more than two finger gesture");
268 return;
269 }
270 int32_t id = touchEvent->GetPointerId();
271 PointerEvent::PointerItem item;
272 touchEvent->GetPointerItem(id, item);
273 auto pos = std::find_if(std::begin(fingerGesture_.touches), std::end(fingerGesture_.touches),
274 [id](const auto& item) { return item.id == id; });
275 if (pos == std::end(fingerGesture_.touches)) {
276 MMI_HILOGE("Cant't find the pointer id");
277 return;
278 }
279 auto dx = std::abs(pos->x - item.GetDisplayX());
280 auto dy = std::abs(pos->y - item.GetDisplayY());
281 auto moveDistance = sqrt(pow(dx, TWO_FINGER) + pow(dy, TWO_FINGER));
282 if (moveDistance > TOUCH_MOVE_THRESHOLD) {
283 MMI_HILOGD("Finger movement distance greater than 15PX, defaultDistance:%{public}d, moveDistance:%{public}f",
284 TOUCH_MOVE_THRESHOLD, moveDistance);
285 CheckFingerGestureCancelEvent(touchEvent);
286 StopFingerGesture();
287 }
288 }
289
HandleFingerGestureUpEvent(const std::shared_ptr<PointerEvent> touchEvent)290 void LongPressSubscriberHandler::HandleFingerGestureUpEvent(const std::shared_ptr<PointerEvent> touchEvent)
291 {
292 CALL_DEBUG_ENTER;
293 CHKPV(touchEvent);
294 if (isAllTimerClosed) {
295 MMI_HILOGD("Finger gesture has stopped");
296 return;
297 }
298 if (touchEvent->GetPointerIds().size() > static_cast<size_t>(TWO_FINGER)) {
299 MMI_HILOGE("Not support more than two finger gesture");
300 return;
301 }
302 CheckFingerGestureCancelEvent(touchEvent);
303 StopFingerGesture();
304 }
305
CheckFingerGestureCancelEvent(const std::shared_ptr<PointerEvent> touchEvent) const306 void LongPressSubscriberHandler::CheckFingerGestureCancelEvent(const std::shared_ptr<PointerEvent> touchEvent) const
307 {
308 CALL_DEBUG_ENTER;
309 CHKPV(touchEvent);
310 auto fingerCount = touchEvent->GetPointerIds().size();
311 size_t index = fingerCount - 1;
312 if (index < 0 || index > static_cast<size_t>(ONE_FINGER)) {
313 MMI_HILOGE("Not support more than two finger gesture");
314 return;
315 }
316 int64_t currentTime = touchEvent->GetActionTime() - fingerGesture_.touches[index].downTime;
317 if (!durationTimers_.empty()) {
318 if (currentTime < durationTimers_[0].duration * MS_TO_US) {
319 MMI_HILOGD("The current time is earlier than the minimum delay, the cancel event does not need to be sent");
320 return;
321 }
322 }
323
324 for (auto it = sessManager_.begin(); it != sessManager_.end(); ++it) {
325 const std::vector<std::shared_ptr<Subscriber>> &subscribers = it->second;
326 std::vector<std::shared_ptr<Subscriber>> tempSubs;
327 for (auto iter = subscribers.begin(); iter != subscribers.end(); ++iter) {
328 if (fingerCount == static_cast<size_t>((*iter)->fingerCount_)) {
329 tempSubs.push_back(*iter);
330 }
331 }
332 if (tempSubs.size() < static_cast<size_t>(TWO_FINGER)) {
333 continue;
334 }
335 for (size_t i = 0; i + 1 < tempSubs.size(); ++i) {
336 if (currentTime < (tempSubs[i]->duration_ * MS_TO_US)) {
337 break;
338 }
339 if ((currentTime > (tempSubs[i]->duration_ * MS_TO_US)) &&
340 (currentTime < (tempSubs[i + 1]->duration_ * MS_TO_US))) {
341 OnSubscribeLongPressCancelEvent(it->first, fingerCount, tempSubs[i + 1]->duration_);
342 break;
343 }
344 }
345 }
346 }
347
OnSubscribeLongPressCancelEvent(SessionPtr sess,int32_t fingerCount,int32_t duration) const348 void LongPressSubscriberHandler::OnSubscribeLongPressCancelEvent(SessionPtr sess, int32_t fingerCount,
349 int32_t duration) const
350 {
351 CALL_DEBUG_ENTER;
352 auto it = sessManager_.find(sess);
353 if (it == sessManager_.end()) {
354 MMI_HILOGE("Not found the sess");
355 return;
356 }
357 const std::vector<std::shared_ptr<Subscriber>> &subscribers = sessManager_.at(sess);
358 for (const auto &subscriber : subscribers) {
359 if (subscriber->fingerCount_ == fingerCount && subscriber->duration_ == duration) {
360 NotifySubscriber(subscriber, RET_ERR);
361 }
362 }
363 }
364
StartFingerGesture(int32_t fingerCount)365 void LongPressSubscriberHandler::StartFingerGesture(int32_t fingerCount)
366 {
367 CALL_DEBUG_ENTER;
368 for (size_t i = 0; i < durationTimers_.size(); ++i) {
369 durationTimers_[i].timerId = TimerMgr->AddTimer(durationTimers_[i].duration, 1, [this, i, fingerCount]() {
370 durationTimers_[i].timerId = -1;
371 if (!CheckFingerGestureAction(fingerCount)) {
372 return;
373 }
374 OnSubscribeLongPressEvent(fingerCount, durationTimers_[i].duration);
375 });
376 }
377 isAllTimerClosed = false;
378 }
379
StopFingerGesture()380 void LongPressSubscriberHandler::StopFingerGesture()
381 {
382 CALL_DEBUG_ENTER;
383 for (auto &durationTimer : durationTimers_) {
384 if (durationTimer.timerId != -1) {
385 TimerMgr->RemoveTimer(durationTimer.timerId);
386 durationTimer.timerId = -1;
387 }
388 }
389 isAllTimerClosed = true;
390 }
391
CheckFingerGestureAction(int32_t fingerCount) const392 bool LongPressSubscriberHandler::CheckFingerGestureAction(int32_t fingerCount) const
393 {
394 CALL_DEBUG_ENTER;
395 auto displayInfo = WIN_MGR->GetDefaultDisplayInfo();
396 CHKPR(displayInfo, false);
397 auto leftLimit = ConvertVPToPX(TOUCH_LIFT_LIMIT);
398 auto rightLimit = displayInfo->width - ConvertVPToPX(TOUCH_RIGHT_LIMIT);
399 auto topLimit = ConvertVPToPX(TOUCH_TOP_LIMIT);
400 auto bottomLimit = displayInfo->height - ConvertVPToPX(TOUCH_BOTTOM_LIMIT);
401
402 auto firstFinger = fingerGesture_.touches[0];
403 if (firstFinger.x <= leftLimit || firstFinger.x >= rightLimit ||
404 firstFinger.y <= topLimit || firstFinger.y >= bottomLimit) {
405 MMI_HILOGI("Any finger out of region");
406 return false;
407 }
408 if (fingerCount == TWO_FINGER) {
409 auto secondFinger = fingerGesture_.touches[1];
410 if (secondFinger.x <= leftLimit || secondFinger.x >= rightLimit ||
411 secondFinger.y <= topLimit || secondFinger.y >= bottomLimit) {
412 MMI_HILOGI("Any finger out of region");
413 return false;
414 }
415 auto devX = firstFinger.x - secondFinger.x;
416 auto devY = firstFinger.y - secondFinger.y;
417 auto distance = sqrt(pow(devX, TWO_FINGER) + pow(devY, TWO_FINGER));
418 if (distance < ConvertVPToPX(TWO_FINGERS_DISTANCE_LIMIT)) {
419 MMI_HILOGI("Two fingers distance:%{public}f too small", distance);
420 return false;
421 }
422 }
423 return true;
424 }
425
InitSessionDeleteCallback()426 bool LongPressSubscriberHandler::InitSessionDeleteCallback()
427 {
428 CALL_DEBUG_ENTER;
429 if (callbackInitialized_) {
430 MMI_HILOGD("Session delete callback has already been initialized");
431 return true;
432 }
433 auto udsServerPtr = InputHandler->GetUDSServer();
434 CHKPF(udsServerPtr);
435 std::function<void(SessionPtr)> callback =
436 [this] (SessionPtr sess) { return this->OnSessionDelete(sess); };
437 udsServerPtr->AddSessionDeletedCallback(callback);
438 callbackInitialized_ = true;
439 return true;
440 }
441
ConvertVPToPX(int32_t vp) const442 int32_t LongPressSubscriberHandler::ConvertVPToPX(int32_t vp) const
443 {
444 if (vp <= 0) {
445 return 0;
446 }
447 auto displayInfo = WIN_MGR->GetDefaultDisplayInfo();
448 CHKPR(displayInfo, 0);
449 int32_t dpi = displayInfo->dpi;
450 if (dpi <= 0) {
451 return 0;
452 }
453 return vp * (dpi / PX_BASE);
454 }
455
GetBundleName(std::string & bundleName,int32_t windowPid) const456 int32_t LongPressSubscriberHandler::GetBundleName(std::string &bundleName, int32_t windowPid) const
457 {
458 CALL_DEBUG_ENTER;
459 auto appMgrClient = DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance();
460 CHKPR(appMgrClient, ERROR_NULL_POINTER);
461 int32_t userid = WIN_MGR->GetCurrentUserId();
462 if (userid < 0) {
463 userid = DEFAULT_USER_ID;
464 }
465 auto udsServer = InputHandler->GetUDSServer();
466 CHKPR(udsServer, RET_ERR);
467 auto sess = udsServer->GetSessionByPid(windowPid);
468 if (sess != nullptr) {
469 bundleName = sess->GetProgramName();
470 return RET_OK;
471 }
472 return RET_ERR;
473 }
474
NotifySubscriber(std::shared_ptr<Subscriber> subscriber,int32_t result) const475 void LongPressSubscriberHandler::NotifySubscriber(std::shared_ptr<Subscriber> subscriber, int32_t result) const
476 {
477 CALL_DEBUG_ENTER;
478 CHKPV(subscriber);
479 auto udsServerPtr = InputHandler->GetUDSServer();
480 CHKPV(udsServerPtr);
481 if (subscriber->sess_ == nullptr) {
482 MMI_HILOGE("Subscriber's sess is null");
483 return;
484 }
485 int32_t windowPid = WIN_MGR->GetWindowPid(touchEvent_->GetTargetWindowId());
486 if (windowPid == RET_ERR) {
487 MMI_HILOGE("Get window pid failed");
488 return;
489 }
490
491 std::string bundleName;
492 if (GetBundleName(bundleName, windowPid) == RET_ERR) {
493 MMI_HILOGE("Failed to get bundle name, pid %{public}d", windowPid);
494 }
495 int32_t id = touchEvent_->GetPointerId();
496 PointerEvent::PointerItem item;
497 touchEvent_->GetPointerItem(id, item);
498 LongPressEvent longPressEvent = {
499 .fingerCount = subscriber->fingerCount_,
500 .duration = subscriber->duration_,
501 .pid = windowPid,
502 .displayId = touchEvent_->GetTargetDisplayId(),
503 .displayX = fingerGesture_.touches[0].x,
504 .displayY = fingerGesture_.touches[0].y,
505 .result = result,
506 .windowId = touchEvent_->GetTargetWindowId(),
507 .pointerId = touchEvent_->GetPointerId(),
508 .downTime = item.GetDownTime(),
509 .bundleName = bundleName,
510 };
511
512 NetPacket pkt(MmiMessageId::ON_SUBSCRIBE_LONG_PRESS);
513 InputEventDataTransformation::LongPressEventToNetPacket(longPressEvent, pkt);
514 int32_t fd = subscriber->sess_->GetFd();
515 pkt << fd << subscriber->id_;
516 MMI_HILOGI("Notify subscriber id:%{public}d, pid:%{public}d", subscriber->id_, subscriber->sess_->GetPid());
517 if (pkt.ChkRWError()) {
518 MMI_HILOGE("Packet write dispatch subscriber failed");
519 return;
520 }
521 if (!udsServerPtr->SendMsg(fd, pkt)) {
522 MMI_HILOGE("Leave, server dispatch subscriber failed");
523 }
524 }
525 } // namespace MMI
526 } // namespace OHOS
527