• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 <map>
17 #include "accessibility_screen_touch.h"
18 #include "accessibility_circle_drawing_manager.h"
19 #include "accessible_ability_manager_service.h"
20 #include "hilog_wrapper.h"
21 
22 namespace OHOS {
23 namespace Accessibility {
24 
25 constexpr int32_t POINTER_COUNT_1 = 1;
26 constexpr int32_t DISPLAY_WIDTH_RATIO = 150;
27 
28 constexpr uint32_t CLICK_RESPONSE_DELAY_SHORT = 0;
29 constexpr uint32_t CLICK_RESPONSE_DELAY_MEDIUM = 1;
30 constexpr uint32_t CLICK_RESPONSE_DELAY_LONG = 2;
31 
32 constexpr uint32_t CLICK_RESPONSE_TIME_SHORT = 0; // ms
33 constexpr uint32_t CLICK_RESPONSE_TIME_MEDIUM = 300; // ms
34 constexpr uint32_t CLICK_RESPONSE_TIME_LONG = 600; // ms
35 
36 constexpr uint32_t IGNORE_REPEAT_CLICK_SHORTEST = 0;
37 constexpr uint32_t IGNORE_REPEAT_CLICK_SHORT = 1;
38 constexpr uint32_t IGNORE_REPEAT_CLICK_MEDIUM = 2;
39 constexpr uint32_t IGNORE_REPEAT_CLICK_LONG = 3;
40 constexpr uint32_t IGNORE_REPEAT_CLICK_LONGEST = 4;
41 
42 constexpr uint32_t IGNORE_REPEAT_CLICK_TIME_SHORTEST = 100; // ms
43 constexpr uint32_t IGNORE_REPEAT_CLICK_TIME_SHORT = 400; // ms
44 constexpr uint32_t IGNORE_REPEAT_CLICK_TIME_MEDIUM = 700; // ms
45 constexpr uint32_t IGNORE_REPEAT_CLICK_TIME_LONG = 1000; // ms
46 constexpr uint32_t IGNORE_REPEAT_CLICK_TIME_LONGEST = 1300; // ms
47 
48 constexpr uint32_t CIRCLE_ANGLE = 360;
49 
50 constexpr uint32_t NUMBER_10 = 10;
51 
52 constexpr uint64_t FOLD_SCREEN_ID = 5; // fold screen main screen id 5
53 
54 const std::map<uint32_t, uint32_t> CLICK_RESPONSE_TIME_MAP = {
55     {CLICK_RESPONSE_DELAY_SHORT, CLICK_RESPONSE_TIME_SHORT},
56     {CLICK_RESPONSE_DELAY_MEDIUM, CLICK_RESPONSE_TIME_MEDIUM},
57     {CLICK_RESPONSE_DELAY_LONG, CLICK_RESPONSE_TIME_LONG}
58 };
59 
60 const std::map<uint32_t, uint32_t> IGNORE_REPEAT_CLICK_TIME_MAP = {
61     {IGNORE_REPEAT_CLICK_SHORTEST, IGNORE_REPEAT_CLICK_TIME_SHORTEST},
62     {IGNORE_REPEAT_CLICK_SHORT, IGNORE_REPEAT_CLICK_TIME_SHORT},
63     {IGNORE_REPEAT_CLICK_MEDIUM, IGNORE_REPEAT_CLICK_TIME_MEDIUM},
64     {IGNORE_REPEAT_CLICK_LONG, IGNORE_REPEAT_CLICK_TIME_LONG},
65     {IGNORE_REPEAT_CLICK_LONGEST, IGNORE_REPEAT_CLICK_TIME_LONGEST}
66 };
67 
68 int64_t AccessibilityScreenTouch::lastUpTime = 0; // global last up time
69 
AccessibilityScreenTouch()70 AccessibilityScreenTouch::AccessibilityScreenTouch()
71 {
72     HILOG_DEBUG();
73     // get from account data directly
74     sptr<AccessibilityAccountData> accountData =
75         Singleton<AccessibleAbilityManagerService>::GetInstance().GetCurrentAccountData();
76     clickResponseTime_ = accountData->GetConfig()->GetClickResponseTime();
77     ignoreRepeatClickState_ = accountData->GetConfig()->GetIgnoreRepeatClickState();
78     ignoreRepeatClickTime_ = accountData->GetConfig()->GetIgnoreRepeatClickTime();
79 
80     if (clickResponseTime_ > 0 && ignoreRepeatClickState_ == true) {
81         currentState_ = BOTH_RESPONSE_DELAY_IGNORE_REPEAT_CLICK;
82     } else if (clickResponseTime_ > 0) {
83         currentState_ = CLICK_RESPONSE_DELAY_STATE;
84     } else if (ignoreRepeatClickState_ == true) {
85         currentState_ = IGNORE_REPEAT_CLICK_STATE;
86     } else {
87         currentState_ = DEFAULT_STATE;
88     }
89 
90     lastUpTime_ = lastUpTime;
91 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
92     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
93     auto display = displayMgr.GetDefaultDisplay();
94     if (!display) {
95         HILOG_ERROR("get display is nullptr");
96         return;
97     }
98 
99     threshold_ = CALCULATION_DIMENSION(display->GetWidth()) / DISPLAY_WIDTH_RATIO;
100 #else
101     HILOG_DEBUG("not support display manager");
102     threshold_ = static_cast<double>(CIRCLE_ANGLE) / DISPLAY_WIDTH_RATIO;
103 #endif
104 }
105 
~AccessibilityScreenTouch()106 AccessibilityScreenTouch::~AccessibilityScreenTouch()
107 {
108     lastUpTime = lastUpTime_;
109     if (drawCircleThread_ && drawCircleThread_->joinable()) {
110         drawCircleThread_->join();
111     }
112     drawCircleThread_ = nullptr;
113     AccessibilityCircleDrawingManager::DeleteInstance();
114 }
115 
GetRealClickResponseTime()116 uint32_t AccessibilityScreenTouch::GetRealClickResponseTime()
117 {
118     auto iter = CLICK_RESPONSE_TIME_MAP.find(clickResponseTime_);
119     if (iter != CLICK_RESPONSE_TIME_MAP.end()) {
120         return iter->second;
121     }
122 
123     return CLICK_RESPONSE_TIME_MAP.at(CLICK_RESPONSE_DELAY_SHORT);
124 }
125 
GetRealIgnoreRepeatClickTime()126 uint32_t AccessibilityScreenTouch::GetRealIgnoreRepeatClickTime()
127 {
128     auto iter = IGNORE_REPEAT_CLICK_TIME_MAP.find(ignoreRepeatClickTime_);
129     if (iter != IGNORE_REPEAT_CLICK_TIME_MAP.end()) {
130         return iter->second;
131     }
132 
133     return IGNORE_REPEAT_CLICK_TIME_MAP.at(IGNORE_REPEAT_CLICK_SHORTEST);
134 }
135 
GetRealIgnoreRepeatClickState()136 bool AccessibilityScreenTouch::GetRealIgnoreRepeatClickState()
137 {
138     return ignoreRepeatClickState_;
139 }
140 
DrawCircleProgress()141 void AccessibilityScreenTouch::DrawCircleProgress()
142 {
143     HILOG_DEBUG();
144     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
145     uint64_t screenId = displayMgr.GetDefaultDisplayId(); // default screenId 0
146     if (displayMgr.IsFoldable() == true && displayMgr.GetFoldDisplayMode() == Rosen::FoldDisplayMode::MAIN) {
147         HILOG_DEBUG("fold screen and main screen, screenId %{public}" PRIu64 "", FOLD_SCREEN_ID);
148         screenId = FOLD_SCREEN_ID;
149     }
150 
151     AccessibilityCircleDrawingManager::GetInstance()->DrawPointer(circleCenterPhysicalX_,
152         circleCenterPhysicalY_, 0, screenId);
153     AccessibilityCircleDrawingManager::GetInstance()->UpdatePointerVisible(true);
154     uint32_t times = GetRealClickResponseTime() / NUMBER_10;
155     uint32_t step = CIRCLE_ANGLE / times;
156     uint32_t time = 0;
157     while (time < times && isStopDrawCircle_ == false) {
158         AccessibilityCircleDrawingManager::GetInstance()->DrawPointer(circleCenterPhysicalX_,
159             circleCenterPhysicalY_, step * time, screenId);
160         time++;
161         std::this_thread::yield();
162         std::this_thread::sleep_for(std::chrono::milliseconds(NUMBER_10));
163     }
164 
165     AccessibilityCircleDrawingManager::GetInstance()->UpdatePointerVisible(false);
166 }
167 
HandleResponseDelayStateInnerDown(MMI::PointerEvent & event)168 void AccessibilityScreenTouch::HandleResponseDelayStateInnerDown(MMI::PointerEvent &event)
169 {
170     HILOG_DEBUG();
171     MMI::PointerEvent::PointerItem pointerItem;
172     if (!event.GetPointerItem(event.GetPointerId(), pointerItem)) {
173         HILOG_WARN("get GetPointerItem %{public}d failed", event.GetPointerId());
174     }
175 
176     startTime_ = event.GetActionTime();
177     startPointer_ = pointerItem;
178     isMoveBeyondThreshold_ = false;
179     isFirstDownEvent_ = true;
180 
181     circleCenterPhysicalX_ = pointerItem.GetDisplayX();
182     circleCenterPhysicalY_ = pointerItem.GetDisplayY();
183     isStopDrawCircle_ = false;
184     if (drawCircleThread_ && drawCircleThread_->joinable()) {
185         drawCircleThread_->join();
186     }
187 
188     drawCircleThread_ = nullptr;
189     drawCircleThread_ = std::make_shared<std::thread>(&AccessibilityScreenTouch::DrawCircleProgress, this);
190     if (drawCircleThread_ == nullptr) {
191         HILOG_ERROR("create draw circle progress fail");
192     }
193 }
194 
HandleResponseDelayStateInnerMove(MMI::PointerEvent & event)195 void AccessibilityScreenTouch::HandleResponseDelayStateInnerMove(MMI::PointerEvent &event)
196 {
197     HILOG_DEBUG();
198     if (isMoveBeyondThreshold_ == true) {
199         EventTransmission::OnPointerEvent(event);
200         return;
201     }
202 
203     MMI::PointerEvent::PointerItem pointerItem;
204     if (!event.GetPointerItem(event.GetPointerId(), pointerItem)) {
205         HILOG_WARN("get GetPointerItem %{public}d failed", event.GetPointerId());
206     }
207 
208     float offsetX = startPointer_.GetDisplayX() - pointerItem.GetDisplayX();
209     float offsetY = startPointer_.GetDisplayY() - pointerItem.GetDisplayY();
210     double duration = hypot(offsetX, offsetY);
211     if (duration > threshold_) {
212         event.SetPointerAction(MMI::PointerEvent::POINTER_ACTION_DOWN);
213         EventTransmission::OnPointerEvent(event);
214         isMoveBeyondThreshold_ = true;
215         isStopDrawCircle_ = true;
216         return;
217     }
218 
219     if ((startTime_ + static_cast<int64_t>(GetRealClickResponseTime()) * US_TO_MS) >
220         static_cast<int64_t>(event.GetActionTime())) {
221         circleCenterPhysicalX_ = pointerItem.GetDisplayX();
222         circleCenterPhysicalY_ = pointerItem.GetDisplayY();
223         return;
224     }
225 
226     isStopDrawCircle_ = true;
227     if (isFirstDownEvent_ == true) {
228         event.SetPointerAction(MMI::PointerEvent::POINTER_ACTION_DOWN);
229         EventTransmission::OnPointerEvent(event);
230         isFirstDownEvent_ = false;
231         return;
232     }
233 
234     EventTransmission::OnPointerEvent(event);
235 }
236 
HandleResponseDelayStateInnerUp(MMI::PointerEvent & event)237 void AccessibilityScreenTouch::HandleResponseDelayStateInnerUp(MMI::PointerEvent &event)
238 {
239     HILOG_DEBUG();
240     isStopDrawCircle_ = true;
241     if (isMoveBeyondThreshold_ == true) {
242         EventTransmission::OnPointerEvent(event);
243         return;
244     }
245 
246     if ((startTime_ + static_cast<int64_t>(GetRealClickResponseTime()) * US_TO_MS) >
247         static_cast<int64_t>(event.GetActionTime())) {
248         return;
249     }
250 
251     if (isFirstDownEvent_ == true) {
252         return;
253     }
254 
255     EventTransmission::OnPointerEvent(event);
256 }
257 
HandleResponseDelayState(MMI::PointerEvent & event)258 void AccessibilityScreenTouch::HandleResponseDelayState(MMI::PointerEvent &event)
259 {
260     HILOG_DEBUG();
261     if (event.GetPointerIds().size() > POINTER_COUNT_1) {
262         return;
263     }
264 
265     switch (event.GetPointerAction()) {
266         case MMI::PointerEvent::POINTER_ACTION_DOWN:
267             HandleResponseDelayStateInnerDown(event);
268             break;
269         case MMI::PointerEvent::POINTER_ACTION_MOVE:
270             HandleResponseDelayStateInnerMove(event);
271             break;
272         case MMI::PointerEvent::POINTER_ACTION_UP:
273             HandleResponseDelayStateInnerUp(event);
274             break;
275         default:
276             break;
277     }
278 }
279 
HandleIgnoreRepeatClickStateInnerDown(MMI::PointerEvent & event)280 void AccessibilityScreenTouch::HandleIgnoreRepeatClickStateInnerDown(MMI::PointerEvent &event)
281 {
282     HILOG_DEBUG();
283     if (event.GetPointerIds().size() > POINTER_COUNT_1) {
284         return;
285     }
286 
287     int64_t downTime = event.GetActionTime();
288     if ((downTime - lastUpTime_) / US_TO_MS < GetRealIgnoreRepeatClickTime()) {
289         isInterceptClick_ = true;
290         return;
291     }
292 
293     EventTransmission::OnPointerEvent(event);
294     isInterceptClick_ = false;
295 }
296 
HandleIgnoreRepeatClickStateInnerMove(MMI::PointerEvent & event)297 void AccessibilityScreenTouch::HandleIgnoreRepeatClickStateInnerMove(MMI::PointerEvent &event)
298 {
299     HILOG_DEBUG();
300     if (event.GetPointerIds().size() > POINTER_COUNT_1) {
301         return;
302     }
303 
304     if (isInterceptClick_ == false) {
305         EventTransmission::OnPointerEvent(event);
306     }
307 }
308 
HandleIgnoreRepeatClickStateInnerUp(MMI::PointerEvent & event)309 void AccessibilityScreenTouch::HandleIgnoreRepeatClickStateInnerUp(MMI::PointerEvent &event)
310 {
311     HILOG_DEBUG();
312     if (event.GetPointerIds().size() > POINTER_COUNT_1) {
313         return;
314     }
315 
316     if (isInterceptClick_ == false) {
317         EventTransmission::OnPointerEvent(event);
318         lastUpTime_ = event.GetActionTime();
319     }
320 }
321 
HandleIgnoreRepeatClickState(MMI::PointerEvent & event)322 void AccessibilityScreenTouch::HandleIgnoreRepeatClickState(MMI::PointerEvent &event)
323 {
324     HILOG_DEBUG();
325     switch (event.GetPointerAction()) {
326         case MMI::PointerEvent::POINTER_ACTION_DOWN:
327             HandleIgnoreRepeatClickStateInnerDown(event);
328             break;
329         case MMI::PointerEvent::POINTER_ACTION_MOVE:
330             HandleIgnoreRepeatClickStateInnerMove(event);
331             break;
332         case MMI::PointerEvent::POINTER_ACTION_UP:
333             HandleIgnoreRepeatClickStateInnerUp(event);
334             break;
335         default:
336             break;
337     }
338 }
339 
HandleBothStateInnerDown(MMI::PointerEvent & event)340 void AccessibilityScreenTouch::HandleBothStateInnerDown(MMI::PointerEvent &event)
341 {
342     HILOG_DEBUG();
343     if (event.GetPointerIds().size() > POINTER_COUNT_1) {
344         return;
345     }
346 
347     int64_t downTime = event.GetActionTime();
348     if ((downTime - lastUpTime_) / US_TO_MS < GetRealIgnoreRepeatClickTime()) {
349         isInterceptClick_ = true;
350         return;
351     }
352 
353     HandleResponseDelayStateInnerDown(event);
354     isInterceptClick_ = false;
355 }
356 
HandleBothStateInnerMove(MMI::PointerEvent & event)357 void AccessibilityScreenTouch::HandleBothStateInnerMove(MMI::PointerEvent &event)
358 {
359     HILOG_DEBUG();
360     if (event.GetPointerIds().size() > POINTER_COUNT_1) {
361         return;
362     }
363 
364     if (isInterceptClick_ == true) {
365         return;
366     }
367 
368     HandleResponseDelayStateInnerMove(event);
369 }
370 
HandleBothStateInnerUp(MMI::PointerEvent & event)371 void AccessibilityScreenTouch::HandleBothStateInnerUp(MMI::PointerEvent &event)
372 {
373     HILOG_DEBUG();
374     if (event.GetPointerIds().size() > POINTER_COUNT_1) {
375         return;
376     }
377 
378     if (isInterceptClick_ == true) {
379         return;
380     }
381 
382     lastUpTime_ = event.GetActionTime();
383     HandleResponseDelayStateInnerUp(event);
384 }
385 
HandleBothState(MMI::PointerEvent & event)386 void AccessibilityScreenTouch::HandleBothState(MMI::PointerEvent &event)
387 {
388     HILOG_DEBUG();
389     switch (event.GetPointerAction()) {
390         case MMI::PointerEvent::POINTER_ACTION_DOWN:
391             HandleBothStateInnerDown(event);
392             break;
393         case MMI::PointerEvent::POINTER_ACTION_MOVE:
394             HandleBothStateInnerMove(event);
395             break;
396         case MMI::PointerEvent::POINTER_ACTION_UP:
397             HandleBothStateInnerUp(event);
398             break;
399         default:
400             break;
401     }
402 }
403 
Clear()404 void AccessibilityScreenTouch::Clear()
405 {
406     isMoveBeyondThreshold_ = false;
407     isInterceptClick_ = false;
408     startPointer_ = {};
409 }
410 
OnPointerEvent(MMI::PointerEvent & event)411 bool AccessibilityScreenTouch::OnPointerEvent(MMI::PointerEvent &event)
412 {
413     HILOG_DEBUG();
414     if (event.GetSourceType() != MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN) {
415         EventTransmission::OnPointerEvent(event);
416         return false;
417     }
418 
419     if (event.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_CANCEL) {
420         Clear();
421         return true;
422     }
423 
424     switch (currentState_) {
425         case ScreenTouchState::CLICK_RESPONSE_DELAY_STATE:
426             HandleResponseDelayState(event);
427             break;
428         case ScreenTouchState::IGNORE_REPEAT_CLICK_STATE:
429             HandleIgnoreRepeatClickState(event);
430             break;
431         case ScreenTouchState::BOTH_RESPONSE_DELAY_IGNORE_REPEAT_CLICK:
432             HandleBothState(event);
433             break;
434         case ScreenTouchState::DEFAULT_STATE:
435         default:
436             EventTransmission::OnPointerEvent(event);
437     }
438 
439     return true;
440 }
441 } // namespace Accessibility
442 } // namespace OHOS