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_zoom_gesture.h"
17 #include "accessible_ability_manager_service.h"
18 #include "hilog_wrapper.h"
19 #include "window_accessibility_controller.h"
20 #include "accessibility_window_manager.h"
21 #include "utils.h"
22 #ifdef OHOS_BUILD_ENABLE_POWER_MANAGER
23 #include "accessibility_power_manager.h"
24 #endif
25 
26 namespace OHOS {
27 namespace Accessibility {
28 namespace {
29     constexpr size_t POINTER_COUNT_1 = 1;
30     constexpr size_t POINTER_COUNT_2 = 2;
31     constexpr float TAP_MIN_DISTANCE = 8.0f;
32     constexpr int32_t MULTI_TAP_TIMER = 250; // ms
33     constexpr int32_t LONG_PRESS_TIMER = 300; // ms
34     constexpr int64_t US_TO_MS = 1000;
35     constexpr float DOUBLE_TAP_SLOP = 100.0f;
36     constexpr float HALF = 0.5f;
37     constexpr uint32_t DOUBLE = 2;
38     constexpr uint32_t TRIPLE_TAP_COUNT = 3;
39     constexpr float DEFAULT_SCALE = 2.0f;
40     constexpr float NORMAL_SCALE = 1.0f;
41     constexpr float MAX_SCALE = 8.0f;
42     constexpr uint32_t INPUT_METHOD_WINDOW_TYPE = 2105;
43     constexpr float EPS = 1e-6;
44     constexpr float MIN_SCROLL_SPAN = 2.0f;
45     constexpr float MIN_SCALE_SPAN = 2.0f;
46     constexpr float DEFAULT_ANCHOR = 0.5f;
47 } // namespace
48 
AccessibilityZoomGesture()49 AccessibilityZoomGesture::AccessibilityZoomGesture()
50 {
51     HILOG_DEBUG();
52 
53     zoomGestureEventHandler_ = std::make_shared<ZoomGestureEventHandler>(
54         Singleton<AccessibleAbilityManagerService>::GetInstance().GetMainRunner(), *this);
55 
56     tapDistance_ = TAP_MIN_DISTANCE;
57 
58 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
59     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
60     auto display = displayMgr.GetDefaultDisplay();
61     if (!display) {
62         HILOG_ERROR("get display is nullptr");
63         return;
64     }
65 
66     float densityPixels = display->GetVirtualPixelRatio();
67     multiTapDistance_ = densityPixels * DOUBLE_TAP_SLOP + 0.5f;
68 #else
69     HILOG_DEBUG("not support display manager");
70     multiTapDistance_ = 1 * DOUBLE_TAP_SLOP + 0.5f;
71 #endif
72 }
73 
IsTapOnInputMethod(MMI::PointerEvent &event)74 bool AccessibilityZoomGesture::IsTapOnInputMethod(MMI::PointerEvent &event)
75 {
76     size_t pointerCount = event.GetPointerIds().size();
77     if (pointerCount != POINTER_COUNT_1) {
78         HILOG_DEBUG("not single finger.");
79         return false;
80     }
81     std::vector<AccessibilityWindowInfo> windowInfos =
82         Singleton<AccessibilityWindowManager>::GetInstance().GetAccessibilityWindows();
83     for (auto &window : windowInfos) {
84         if (window.GetWindowType() == INPUT_METHOD_WINDOW_TYPE) {
85             Rect inputRect = window.GetRectInScreen();
86             int32_t leftTopX = inputRect.GetLeftTopXScreenPostion();
87             int32_t leftTopY = inputRect.GetLeftTopYScreenPostion();
88             int32_t rightBottomX = inputRect.GetRightBottomXScreenPostion();
89             int32_t rightBottomY = inputRect.GetRightBottomYScreenPostion();
90 
91             MMI::PointerEvent::PointerItem item;
92             event.GetPointerItem(event.GetPointerId(), item);
93             int32_t itemX = item.GetDisplayX();
94             int32_t itemY = item.GetDisplayY();
95             if ((itemX >= leftTopX) && (itemX <= rightBottomX) &&
96             (itemY >= leftTopY) && (itemY <= rightBottomY)) {
97                 HILOG_INFO("tap on input method window.");
98                 return true;
99             }
100         }
101     }
102     HILOG_DEBUG("have no input method window.");
103     return false;
104 }
105 
OnPointerEvent(MMI::PointerEvent &event)106 bool AccessibilityZoomGesture::OnPointerEvent(MMI::PointerEvent &event)
107 {
108     HILOG_DEBUG("state_ is %{public}d.", state_);
109 
110     int32_t sourceType = event.GetSourceType();
111     if (sourceType != MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN) {
112         EventTransmission::OnPointerEvent(event);
113         return false;
114     }
115 
116     if (IsTapOnInputMethod(event)) {
117         EventTransmission::OnPointerEvent(event);
118         return true;
119     }
120 
121     switch (state_) {
122         case READY_STATE:
123             CacheEvents(event);
124             RecognizeInReadyState(event);
125             break;
126         case ZOOMIN_STATE:
127             CacheEvents(event);
128             RecognizeInZoomState(event);
129             break;
130         case SLIDING_STATE:
131             RecognizeInSlidingState(event);
132             break;
133         default:
134             break;
135     }
136     return true;
137 }
138 
TransferState(ACCESSIBILITY_ZOOM_STATE state)139 void AccessibilityZoomGesture::TransferState(ACCESSIBILITY_ZOOM_STATE state)
140 {
141     HILOG_DEBUG("old state= %{public}d, new state= %{public}d", state_, state);
142 
143     state_ = state;
144 }
145 
CacheEvents(MMI::PointerEvent &event)146 void AccessibilityZoomGesture::CacheEvents(MMI::PointerEvent &event)
147 {
148     HILOG_DEBUG();
149 
150     int32_t action = event.GetPointerAction();
151     size_t pointerCount = event.GetPointerIds().size();
152     std::shared_ptr<MMI::PointerEvent> pointerEvent = std::make_shared<MMI::PointerEvent>(event);
153 
154     switch (action) {
155         case MMI::PointerEvent::POINTER_ACTION_DOWN:
156             if (pointerCount == POINTER_COUNT_1) {
157                 HILOG_DEBUG("Cache pointer down");
158                 preLastDownEvent_ = lastDownEvent_;
159                 lastDownEvent_ = pointerEvent;
160             }
161             break;
162         case MMI::PointerEvent::POINTER_ACTION_UP:
163             if (pointerCount == POINTER_COUNT_1) {
164                 HILOG_DEBUG("Cache pointer up");
165                 preLastUpEvent_ = lastUpEvent_;
166                 lastUpEvent_ = pointerEvent;
167             }
168             break;
169         case MMI::PointerEvent::POINTER_ACTION_MOVE:
170             if (pointerCount == POINTER_COUNT_1) {
171                 HILOG_DEBUG("Cache pointer move.");
172                 currentMoveEvent_ = pointerEvent;
173             }
174             break;
175         default:
176             HILOG_DEBUG("Action is %{public}d", action);
177             break;
178     }
179     cacheEvents_.emplace_back(pointerEvent);
180 }
181 
SendCacheEventsToNext()182 void AccessibilityZoomGesture::SendCacheEventsToNext()
183 {
184     HILOG_DEBUG();
185 
186     bool isStartNewAction = false;
187     int32_t action = MMI::PointerEvent::POINTER_ACTION_UNKNOWN;
188     std::vector<std::shared_ptr<MMI::PointerEvent>> cacheEventsTmp;
189     std::copy(cacheEvents_.begin(), cacheEvents_.end(), std::back_inserter(cacheEventsTmp));
190 
191     ClearCacheEventsAndMsg();
192 
193     size_t cacheEventsNum = 0;
194     size_t cacheEventsTotalNum = cacheEventsTmp.size();
195     for (auto &pointerEvent : cacheEventsTmp) {
196         cacheEventsNum++;
197         action = pointerEvent->GetPointerAction();
198         if ((cacheEventsNum > 1) &&
199             (cacheEventsNum == cacheEventsTotalNum) &&
200             (action == MMI::PointerEvent::POINTER_ACTION_DOWN)) {
201             HILOG_DEBUG("The down event needs to be parsed again");
202             isStartNewAction = true;
203         }
204         if (isStartNewAction) {
205             OnPointerEvent(*pointerEvent);
206         } else {
207             pointerEvent->SetActionTime(Utils::GetSystemTime() * US_TO_MS);
208             EventTransmission::OnPointerEvent(*pointerEvent);
209         }
210     }
211 }
212 
ClearCacheEventsAndMsg()213 void AccessibilityZoomGesture::ClearCacheEventsAndMsg()
214 {
215     HILOG_DEBUG();
216 
217     cacheEvents_.clear();
218     preLastDownEvent_ = nullptr;
219     lastDownEvent_ = nullptr;
220     preLastUpEvent_ = nullptr;
221     lastUpEvent_ = nullptr;
222     zoomGestureEventHandler_->RemoveEvent(MULTI_TAP_MSG);
223 }
224 
RecognizeInReadyState(MMI::PointerEvent &event)225 void AccessibilityZoomGesture::RecognizeInReadyState(MMI::PointerEvent &event)
226 {
227     HILOG_DEBUG();
228 
229     int32_t action = event.GetPointerAction();
230     size_t pointerCount = event.GetPointerIds().size();
231     bool isTripleTaps = false;
232 
233     HILOG_DEBUG("action:%{public}d, pointerCount:%{public}zu", action, pointerCount);
234     switch (action) {
235         case MMI::PointerEvent::POINTER_ACTION_DOWN:
236             zoomGestureEventHandler_->RemoveEvent(MULTI_TAP_MSG);
237             if ((pointerCount == POINTER_COUNT_1) && IsDownValid()) {
238                 zoomGestureEventHandler_->SendEvent(MULTI_TAP_MSG, 0, MULTI_TAP_TIMER);
239             } else {
240                 SendCacheEventsToNext();
241             }
242             break;
243         case MMI::PointerEvent::POINTER_ACTION_UP:
244             if ((pointerCount == POINTER_COUNT_1) && IsUpValid()) {
245                 isTripleTaps = IsTripleTaps();
246             } else {
247                 SendCacheEventsToNext();
248                 HILOG_DEBUG("action:%{public}d, pointerCount:%{public}zu", action, pointerCount);
249             }
250             break;
251         case MMI::PointerEvent::POINTER_ACTION_MOVE:
252             if ((pointerCount == POINTER_COUNT_1) && IsMoveValid()) {
253                 HILOG_DEBUG("move valid.");
254             } else {
255                 SendCacheEventsToNext();
256                 HILOG_DEBUG("action:%{public}d, pointerCount:%{public}zu", action, pointerCount);
257             }
258             break;
259         case MMI::PointerEvent::POINTER_ACTION_CANCEL:
260             SendCacheEventsToNext();
261             break;
262         default:
263             break;
264     }
265 
266     if (isTripleTaps) {
267         OnTripleTaps(event);
268     }
269 }
270 
RecognizeInZoomStateDownEvent(MMI::PointerEvent &event)271 void AccessibilityZoomGesture::RecognizeInZoomStateDownEvent(MMI::PointerEvent &event)
272 {
273     HILOG_DEBUG();
274 
275     std::vector<int32_t> pointerIdList = event.GetPointerIds();
276     size_t pointerCount = pointerIdList.size();
277     zoomGestureEventHandler_->RemoveEvent(MULTI_TAP_MSG);
278     if (pointerCount == POINTER_COUNT_1) {
279         isLongPress_ = false;
280         std::shared_ptr<MMI::PointerEvent> pointerEvent = std::make_shared<MMI::PointerEvent>(event);
281         longPressDownEvent_ = pointerEvent;
282         downPid_ = event.GetPointerId();
283         if (IsDownValid()) {
284             zoomGestureEventHandler_->SendEvent(MULTI_TAP_MSG, 0, MULTI_TAP_TIMER);
285         } else {
286             SendCacheEventsToNext();
287         }
288     } else if (pointerCount == POINTER_COUNT_2) {
289         if (isLongPress_ || IsKnuckles(event)) {
290             HILOG_INFO("not transferState sliding.");
291             SendCacheEventsToNext();
292         } else {
293             TransferState(SLIDING_STATE);
294             ClearCacheEventsAndMsg();
295             ZOOM_FOCUS_COORDINATE focusXY = {0.0f, 0.0f};
296             CalcFocusCoordinate(event, focusXY);
297             lastScrollFocusX_ = focusXY.centerX;
298             lastScrollFocusY_ = focusXY.centerY;
299             float span = CalcScaleSpan(event, focusXY);
300             preSpan_ = lastSpan_ = span;
301         }
302     } else {
303         HILOG_INFO("invalid pointer count.");
304     }
305 }
306 
RecognizeInZoomState(MMI::PointerEvent &event)307 void AccessibilityZoomGesture::RecognizeInZoomState(MMI::PointerEvent &event)
308 {
309     HILOG_DEBUG();
310 
311     int32_t action = event.GetPointerAction();
312     std::vector<int32_t> pointerIdList = event.GetPointerIds();
313     size_t pointerCount = pointerIdList.size();
314     bool isTripleTaps = false;
315 
316     HILOG_DEBUG("action:%{public}d, pointerCount:%{public}zu", action, pointerCount);
317     switch (action) {
318         case MMI::PointerEvent::POINTER_ACTION_DOWN:
319             RecognizeInZoomStateDownEvent(event);
320             break;
321         case MMI::PointerEvent::POINTER_ACTION_UP:
322             if (downPid_ == event.GetPointerId()) {
323                 isLongPress_ = false;
324             }
325             if ((pointerCount == POINTER_COUNT_1) && IsUpValid()) {
326                 isTripleTaps = IsTripleTaps();
327             } else {
328                 SendCacheEventsToNext();
329             }
330             break;
331         case MMI::PointerEvent::POINTER_ACTION_MOVE:
332             if ((pointerCount == POINTER_COUNT_1) && !IsLongPress() && IsMoveValid()) {
333                 HILOG_DEBUG("move valid.");
334             } else {
335                 SendCacheEventsToNext();
336                 HILOG_DEBUG("action:%{public}d, pointerCount:%{public}zu", action, pointerCount);
337             }
338             break;
339         case MMI::PointerEvent::POINTER_ACTION_CANCEL:
340             SendCacheEventsToNext();
341             HILOG_DEBUG("action:%{public}d", action);
342             break;
343         default:
344             break;
345     }
346 
347     if (isTripleTaps) {
348         OnTripleTaps(event);
349     }
350 }
351 
RecognizeInSlidingState(MMI::PointerEvent &event)352 void AccessibilityZoomGesture::RecognizeInSlidingState(MMI::PointerEvent &event)
353 {
354     HILOG_DEBUG();
355 
356     int32_t action = event.GetPointerAction();
357     size_t pointerCount = event.GetPointerIds().size();
358     ZOOM_FOCUS_COORDINATE coordinate = {0.0f, 0.0f};
359     CalcFocusCoordinate(event, coordinate);
360 
361     if (pointerCount == POINTER_COUNT_2) {
362         RecognizeScale(event, coordinate);
363         RecognizeScroll(event, coordinate);
364     }
365 
366     HILOG_DEBUG("action:%{public}d, pointerCount:%{public}zu", action, pointerCount);
367     switch (action) {
368         case MMI::PointerEvent::POINTER_ACTION_UP:
369             if (pointerCount == POINTER_COUNT_1) {
370                 TransferState(ZOOMIN_STATE);
371             }
372             break;
373         case MMI::PointerEvent::POINTER_ACTION_CANCEL:
374             TransferState(ZOOMIN_STATE);
375             break;
376         default:
377             break;
378     }
379 }
380 
RecognizeScroll(MMI::PointerEvent &event, ZOOM_FOCUS_COORDINATE &coordinate)381 void AccessibilityZoomGesture::RecognizeScroll(MMI::PointerEvent &event, ZOOM_FOCUS_COORDINATE &coordinate)
382 {
383     HILOG_DEBUG();
384 
385     int32_t action = event.GetPointerAction();
386     switch (action) {
387         case MMI::PointerEvent::POINTER_ACTION_DOWN:
388         case MMI::PointerEvent::POINTER_ACTION_UP:
389             lastScrollFocusX_ = coordinate.centerX;
390             lastScrollFocusY_ = coordinate.centerY;
391             break;
392         case MMI::PointerEvent::POINTER_ACTION_MOVE: {
393             float offsetX = coordinate.centerX - lastScrollFocusX_;
394             float offsetY = coordinate.centerY - lastScrollFocusY_;
395             if ((abs(offsetX) > MIN_SCROLL_SPAN) || (abs(offsetY) > MIN_SCROLL_SPAN)) {
396                 lastScrollFocusX_ = coordinate.centerX;
397                 lastScrollFocusY_ = coordinate.centerY;
398                 OnScroll(offsetX, offsetY);
399             }
400             break;
401         }
402         default:
403             break;
404     }
405 }
406 
RecognizeScale(MMI::PointerEvent &event, ZOOM_FOCUS_COORDINATE &coordinate)407 void AccessibilityZoomGesture::RecognizeScale(MMI::PointerEvent &event, ZOOM_FOCUS_COORDINATE &coordinate)
408 {
409     HILOG_DEBUG();
410 
411     int32_t action = event.GetPointerAction();
412     size_t pointerCount = event.GetPointerIds().size();
413     if (((action == MMI::PointerEvent::POINTER_ACTION_UP) && (pointerCount != POINTER_COUNT_2)) ||
414         (action == MMI::PointerEvent::POINTER_ACTION_CANCEL)) {
415         HILOG_DEBUG("Scaling is end");
416         startScaling_ = false;
417         preSpan_ = lastSpan_ = 0;
418         return;
419     }
420 
421     float span = CalcScaleSpan(event, coordinate);
422 
423     if (action == MMI::PointerEvent::POINTER_ACTION_MOVE) {
424         if (abs(preSpan_ - span) >= MIN_SCALE_SPAN) {
425             startScaling_ = true;
426             HILOG_DEBUG("start scaling.");
427         }
428     }
429     if (!startScaling_) {
430         // When the span is greater than or equal to MIN_SCALE_SPAN, start scaling.
431         if (abs(preSpan_ - span) >= MIN_SCALE_SPAN) {
432             startScaling_ = true;
433             HILOG_DEBUG("start scaling.");
434         }
435     } else {
436         // When the span is smaller than the MIN_SCALE_SPAN,
437         // the scale recognition will be restarted.
438         if (abs(lastSpan_ - span) < 1) {
439             startScaling_ = false;
440             preSpan_ = lastSpan_ = span;
441         }
442         if ((action == MMI::PointerEvent::POINTER_ACTION_UP) ||
443             (action == MMI::PointerEvent::POINTER_ACTION_DOWN)) {
444             preSpan_ = lastSpan_ = span;
445         }
446     }
447 
448     if (!startScaling_) {
449         HILOG_DEBUG("Current is not scaling");
450         return;
451     }
452 
453     if (action != MMI::PointerEvent::POINTER_ACTION_MOVE) {
454         HILOG_DEBUG("Action(%{public}d) is not move", action);
455         return;
456     }
457 
458     float scaleSpan = (span - lastSpan_) * scaleRatio_;
459     if (abs(scaleSpan) > EPS) {
460         OnScale(scaleSpan);
461         lastSpan_ = span;
462     }
463 }
464 
CalcFocusCoordinate(MMI::PointerEvent &event, ZOOM_FOCUS_COORDINATE &coordinate)465 void AccessibilityZoomGesture::CalcFocusCoordinate(MMI::PointerEvent &event, ZOOM_FOCUS_COORDINATE &coordinate)
466 {
467     HILOG_DEBUG();
468 
469     float sumX = 0.0f;
470     float sumY = 0.0f;
471     int32_t upPointerId = -1;
472     int32_t action = event.GetPointerAction();
473     std::vector<int32_t> pointerIdList = event.GetPointerIds();
474     size_t count = pointerIdList.size();
475     if (!count) {
476         HILOG_DEBUG("The size of PointerIds is 0");
477         return;
478     }
479 
480     if (action == MMI::PointerEvent::POINTER_ACTION_UP) {
481         upPointerId = event.GetPointerId();
482         HILOG_DEBUG("The pointer id of up is %{public}d", upPointerId);
483         count--;
484     }
485 
486     if (!count) {
487         HILOG_DEBUG("The size of PointerIds(down) is invalid");
488         return;
489     }
490 
491     for (int32_t pointerId : pointerIdList) {
492         if (pointerId == upPointerId) {
493             continue;
494         }
495         MMI::PointerEvent::PointerItem item;
496         event.GetPointerItem(pointerId, item);
497         sumX += static_cast<float>(item.GetRawDisplayX());
498         sumY += static_cast<float>(item.GetRawDisplayY());
499     }
500 
501     coordinate.centerX = sumX / count;
502     coordinate.centerY = sumY / count;
503     HILOG_DEBUG("centerX:%{public}f, centerY:%{public}f", coordinate.centerX, coordinate.centerY);
504 }
505 
CalcScaleSpan(MMI::PointerEvent &event, ZOOM_FOCUS_COORDINATE coordinate)506 float AccessibilityZoomGesture::CalcScaleSpan(MMI::PointerEvent &event, ZOOM_FOCUS_COORDINATE coordinate)
507 {
508     HILOG_DEBUG();
509 
510     float span = 0.0f;
511     float sumSpanX = 0.0f;
512     float sumSpanY = 0.0f;
513     int32_t upPointerId = -1;
514     int32_t action = event.GetPointerAction();
515     std::vector<int32_t> pointerIdList = event.GetPointerIds();
516     size_t count = pointerIdList.size();
517     if (!count) {
518         HILOG_DEBUG("The size of PointerIds is 0");
519         return span;
520     }
521 
522     if (action == MMI::PointerEvent::POINTER_ACTION_UP) {
523         upPointerId = event.GetPointerId();
524         HILOG_DEBUG("The pointer id of up is %{public}d", upPointerId);
525         count--;
526     }
527 
528     if (!count) {
529         HILOG_DEBUG("The size of PointerIds(down) is invalid");
530         return span;
531     }
532 
533     for (int32_t pointerId : pointerIdList) {
534         if (pointerId == upPointerId) {
535             continue;
536         }
537         MMI::PointerEvent::PointerItem item;
538         event.GetPointerItem(pointerId, item);
539         sumSpanX += static_cast<float>(abs(item.GetRawDisplayX() - coordinate.centerX));
540         sumSpanY += static_cast<float>(abs(item.GetRawDisplayY() - coordinate.centerY));
541     }
542 
543     float spanX = sumSpanX / count;
544     float spanY = sumSpanY / count;
545     span = hypot(spanX, spanY) / HALF;
546     HILOG_DEBUG("The span is %{public}f", span);
547     return span;
548 }
549 
IsDownValid()550 bool AccessibilityZoomGesture::IsDownValid()
551 {
552     HILOG_DEBUG();
553 
554     if (!preLastDownEvent_) {
555         HILOG_DEBUG("This is the first down event");
556         return true;
557     }
558 
559     if (CalcSeparationDistance(preLastDownEvent_, lastDownEvent_) >= multiTapDistance_) {
560         HILOG_DEBUG("The down event is vailid");
561         return false;
562     }
563     return true;
564 }
565 
IsUpValid()566 bool AccessibilityZoomGesture::IsUpValid()
567 {
568     HILOG_DEBUG();
569 
570     if (!lastDownEvent_) {
571         HILOG_DEBUG("The up event is invailid");
572         return false;
573     }
574 
575     if (CalcIntervalTime(lastDownEvent_, lastUpEvent_) >= LONG_PRESS_TIMER) {
576         HILOG_DEBUG("The time has exceeded the long press time");
577         return false;
578     }
579 
580     if (CalcSeparationDistance(lastDownEvent_, lastUpEvent_) >= tapDistance_) {
581         HILOG_DEBUG("The distance has exceeded the threshold");
582         return false;
583     }
584     return true;
585 }
586 
IsMoveValid()587 bool AccessibilityZoomGesture::IsMoveValid()
588 {
589     HILOG_DEBUG();
590 
591     if (!lastDownEvent_) {
592         HILOG_DEBUG("The move event is invailid");
593         return false;
594     }
595 
596     if (CalcIntervalTime(lastDownEvent_, currentMoveEvent_) >= LONG_PRESS_TIMER) {
597         HILOG_DEBUG("The time has exceeded the long press time");
598         return false;
599     }
600 
601     if (CalcSeparationDistance(lastDownEvent_, currentMoveEvent_) >= tapDistance_) {
602         HILOG_DEBUG("The distance has exceeded the threshold");
603         return false;
604     }
605     return true;
606 }
607 
IsLongPress()608 bool AccessibilityZoomGesture::IsLongPress()
609 {
610     HILOG_DEBUG();
611 
612     if (CalcIntervalTime(longPressDownEvent_, currentMoveEvent_) >= LONG_PRESS_TIMER) {
613         HILOG_DEBUG("The time has exceeded the long press time");
614         isLongPress_ = true;
615         return true;
616     }
617     return false;
618 }
619 
IsKnuckles(MMI::PointerEvent &event)620 bool AccessibilityZoomGesture::IsKnuckles(MMI::PointerEvent &event)
621 {
622     HILOG_DEBUG();
623 
624     std::vector<int32_t> pointerIdList = event.GetPointerIds();
625     for (int32_t pointerId : pointerIdList) {
626         MMI::PointerEvent::PointerItem item;
627         event.GetPointerItem(pointerId, item);
628         int32_t toolType = item.GetToolType();
629         if (toolType == MMI::PointerEvent::TOOL_TYPE_KNUCKLE) {
630             HILOG_INFO("is knuckle event.");
631             return true;
632         }
633     }
634     return false;
635 }
636 
IsTripleTaps()637 bool AccessibilityZoomGesture::IsTripleTaps()
638 {
639     HILOG_DEBUG();
640 
641     uint32_t upEventCount = 0;
642     int32_t action = MMI::PointerEvent::POINTER_ACTION_UNKNOWN;
643     for (auto &pointerEvent : cacheEvents_) {
644         action = pointerEvent->GetPointerAction();
645         if (action == MMI::PointerEvent::POINTER_ACTION_UP) {
646             upEventCount++;
647         }
648     }
649 
650     if (upEventCount >= TRIPLE_TAP_COUNT) {
651         HILOG_DEBUG("Triple tap detected");
652         return true;
653     }
654 
655     return false;
656 }
657 
CalcIntervalTime(std::shared_ptr<MMI::PointerEvent> firstEvent, std::shared_ptr<MMI::PointerEvent> secondEvent)658 int64_t AccessibilityZoomGesture::CalcIntervalTime(std::shared_ptr<MMI::PointerEvent> firstEvent,
659     std::shared_ptr<MMI::PointerEvent> secondEvent)
660 {
661     HILOG_DEBUG();
662 
663     if (!firstEvent || !secondEvent) {
664         HILOG_DEBUG("The event is null");
665         return 0;
666     }
667 
668     int64_t firstTime = firstEvent->GetActionTime();
669     int64_t secondTime = secondEvent->GetActionTime();
670     int64_t intervalTime = (secondTime - firstTime) / US_TO_MS;
671 
672     return intervalTime;
673 }
674 
CalcSeparationDistance(std::shared_ptr<MMI::PointerEvent> firstEvent, std::shared_ptr<MMI::PointerEvent> secondEvent)675 float AccessibilityZoomGesture::CalcSeparationDistance(std::shared_ptr<MMI::PointerEvent> firstEvent,
676     std::shared_ptr<MMI::PointerEvent> secondEvent)
677 {
678     HILOG_DEBUG();
679 
680     if (!firstEvent || !secondEvent) {
681         HILOG_DEBUG("The event is null");
682         return 0;
683     }
684 
685     MMI::PointerEvent::PointerItem firstItem;
686     MMI::PointerEvent::PointerItem secondItem;
687     firstEvent->GetPointerItem(firstEvent->GetPointerId(), firstItem);
688     secondEvent->GetPointerItem(secondEvent->GetPointerId(), secondItem);
689     int32_t durationX = secondItem.GetDisplayX() - firstItem.GetDisplayX();
690     int32_t durationY = secondItem.GetDisplayY() - firstItem.GetDisplayY();
691     float distance = static_cast<float>(hypot(durationX, durationY));
692 
693     return distance;
694 }
695 
OnTripleTaps(MMI::PointerEvent &event)696 void AccessibilityZoomGesture::OnTripleTaps(MMI::PointerEvent &event)
697 {
698     HILOG_DEBUG("state_ is %{public}d.", state_);
699 
700     switch (state_) {
701         case READY_STATE: {
702             TransferState(ZOOMIN_STATE);
703             int32_t pointerId = event.GetPointerId();
704             MMI::PointerEvent::PointerItem item;
705             event.GetPointerItem(pointerId, item);
706             int32_t anchorX = item.GetDisplayX();
707             int32_t anchorY = item.GetDisplayY();
708             HILOG_DEBUG("anchorX:%{private}d, anchorY:%{private}d.", anchorX, anchorY);
709             OnZoom(anchorX, anchorY);
710             break;
711         }
712         case ZOOMIN_STATE:
713             TransferState(READY_STATE);
714             OffZoom();
715             break;
716         default:
717             break;
718     }
719 
720     ClearCacheEventsAndMsg();
721 }
722 
ZoomGestureEventHandler( const std::shared_ptr<AppExecFwk::EventRunner> &runner, AccessibilityZoomGesture &zoomGesture)723 AccessibilityZoomGesture::ZoomGestureEventHandler::ZoomGestureEventHandler(
724     const std::shared_ptr<AppExecFwk::EventRunner> &runner,
725     AccessibilityZoomGesture &zoomGesture): AppExecFwk::EventHandler(runner), zoomGesture_(zoomGesture)
726 {
727     HILOG_DEBUG();
728 }
729 
ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)730 void AccessibilityZoomGesture::ZoomGestureEventHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
731 {
732     HILOG_DEBUG();
733 
734     uint32_t eventId = event->GetInnerEventId();
735 
736     switch (eventId) {
737         case MULTI_TAP_MSG:
738             zoomGesture_.SendCacheEventsToNext();
739             break;
740         default:
741             break;
742     }
743 }
744 
GetWindowParam()745 void AccessibilityZoomGesture::GetWindowParam()
746 {
747     HILOG_DEBUG();
748 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
749     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
750     uint64_t currentScreen = displayMgr.GetDefaultDisplayId();
751     OHOS::Rosen::DisplayOrientation currentOrientation = displayMgr.GetOrientation();
752     if ((currentScreen != screenId_) || (currentOrientation != orientation_)) {
753         HILOG_INFO("display id or orientation changed.");
754         screenId_ = currentScreen;
755         orientation_ = currentOrientation;
756         sptr<Rosen::Display> display = displayMgr.GetDisplay(screenId_);
757         screenWidth_ = static_cast<uint32_t>(display->GetWidth());
758         screenHeight_ = static_cast<uint32_t>(display->GetHeight());
759         HILOG_INFO("screenWidth_ = %{public}d, screenHeight_ = %{public}d.", screenWidth_, screenHeight_);
760     }
761     screenSpan_ = hypot(screenWidth_, screenHeight_);
762 #else
763     HILOG_INFO("not support zoom");
764 #endif
765 }
766 
OnZoom(int32_t anchorX, int32_t anchorY)767 void AccessibilityZoomGesture::OnZoom(int32_t anchorX, int32_t anchorY)
768 {
769     HILOG_INFO();
770 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
771     GetWindowParam();
772     if (screenWidth_ == 0 || screenHeight_ == 0) {
773         HILOG_ERROR("screen param invalid.");
774         return;
775     }
776     anchorPointX_ = static_cast<float>(anchorX);
777     anchorPointY_ = static_cast<float>(anchorY);
778 
779     float x = anchorPointX_ / screenWidth_;
780     float y = anchorPointY_ / screenHeight_;
781     scaleRatio_ = DEFAULT_SCALE;
782     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
783     displayMgr.SetDisplayScale(screenId_, scaleRatio_, scaleRatio_, x, y);
784 #else
785     HILOG_INFO("not support zoom");
786     return;
787 #endif
788 }
789 
OffZoom()790 void AccessibilityZoomGesture::OffZoom()
791 {
792     HILOG_INFO();
793 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
794     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
795     uint64_t currentScreen = displayMgr.GetDefaultDisplayId();
796     displayMgr.SetDisplayScale(currentScreen, NORMAL_SCALE, NORMAL_SCALE, DEFAULT_ANCHOR, DEFAULT_ANCHOR);
797 #else
798     HILOG_INFO("not support zoom");
799     return;
800 #endif
801 }
802 
OnScroll(float offsetX, float offsetY)803 void AccessibilityZoomGesture::OnScroll(float offsetX, float offsetY)
804 {
805     HILOG_DEBUG("offsetX:%{public}f, offsetY:%{public}f.", offsetX, offsetY);
806 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
807     GetWindowParam();
808     if (screenWidth_ == 0 || screenHeight_ == 0) {
809         HILOG_ERROR("screen param invalid.");
810         return;
811     }
812 
813     if (abs(scaleRatio_) < EPS) {
814         HILOG_ERROR("scaleRatio_ param invalid.");
815         return;
816     }
817     anchorPointX_ -= (offsetX * DOUBLE / scaleRatio_);
818     anchorPointY_ -= (offsetY * DOUBLE / scaleRatio_);
819 
820     if (anchorPointX_ < 0) {
821         anchorPointX_ = 0;
822     }
823     if (anchorPointX_ > screenWidth_) {
824         anchorPointX_ = screenWidth_;
825     }
826     if (anchorPointY_ < 0) {
827         anchorPointY_ = 0;
828     }
829     if (anchorPointY_ > screenHeight_) {
830         anchorPointY_ = screenHeight_;
831     }
832 
833     float x = anchorPointX_ / screenWidth_;
834     float y = anchorPointY_ / screenHeight_;
835     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
836     displayMgr.SetDisplayScale(screenId_, scaleRatio_, scaleRatio_, x, y);
837 #ifdef OHOS_BUILD_ENABLE_POWER_MANAGER
838     AccessibilityPowerManager &powerMgr = Singleton<AccessibilityPowerManager>::GetInstance();
839     powerMgr.RefreshActivity();
840 #endif
841 #else
842     HILOG_INFO("not support zoom");
843     return;
844 #endif
845 }
846 
OnScale(float scaleSpan)847 void AccessibilityZoomGesture::OnScale(float scaleSpan)
848 {
849     HILOG_DEBUG();
850 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
851     GetWindowParam();
852     if (screenWidth_ == 0 || screenHeight_ == 0 || abs(screenSpan_) < EPS) {
853         HILOG_ERROR("screen param invalid.");
854         return;
855     }
856 
857     float ratio = scaleSpan / screenSpan_;
858     scaleRatio_ = scaleRatio_ + ratio;
859     if (scaleRatio_ > MAX_SCALE) {
860         scaleRatio_ = MAX_SCALE;
861     }
862     if (scaleRatio_ < DEFAULT_SCALE) {
863         scaleRatio_ = DEFAULT_SCALE;
864     }
865 
866     float x = anchorPointX_ / screenWidth_;
867     float y = anchorPointY_ / screenHeight_;
868     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
869     displayMgr.SetDisplayScale(screenId_, scaleRatio_, scaleRatio_, x, y);
870 #else
871     HILOG_INFO("not support zoom");
872     return;
873 #endif
874 }
875 
Clear()876 void AccessibilityZoomGesture::Clear()
877 {
878     HILOG_DEBUG();
879     ClearCacheEventsAndMsg();
880     TransferState(READY_STATE);
881 }
882 
DestroyEvents()883 void AccessibilityZoomGesture::DestroyEvents()
884 {
885     HILOG_INFO();
886     Clear();
887     EventTransmission::DestroyEvents();
888 }
889 } // namespace Accessibility
890 } // namespace OHOS
891