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