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