1 /*
2 * Copyright (c) 2025 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 "pull_throw_subscriber_handler.h"
17
18 #include <parameters.h>
19
20 #include "app_mgr_client.h"
21 #include "bytrace_adapter.h"
22 #include "define_multimodal.h"
23 #include "dfx_hisysevent.h"
24 #include "error_multimodal.h"
25 #include "input_event_data_transformation.h"
26 #include "input_event_handler.h"
27 #include "json_parser.h"
28 #include "key_command_handler.h"
29 #include "key_command_handler_util.h"
30 #include "net_packet.h"
31 #include "proto.h"
32 #include "running_process_info.h"
33 #include "util_ex.h"
34
35 #undef MMI_LOG_DOMAIN
36 #define MMI_LOG_DOMAIN MMI_LOG_HANDLER
37 #undef MMI_LOG_TAG
38 #define MMI_LOG_TAG "PullThrowSubscriberHandler"
39
40 namespace OHOS {
41 namespace MMI {
42 namespace {
43 constexpr int32_t ONE_FINGER { 1 };
44 constexpr int32_t TWO_FINGER { 2 };
45 constexpr int32_t DEFAULT_USER_ID { 100 };
46 constexpr int32_t PX_BASE { 160 };
47 constexpr int32_t MS_TO_US { 1000 };
48
49 }
50
PullThrowSubscriberHandler()51 PullThrowSubscriberHandler::PullThrowSubscriberHandler() {}
52
~PullThrowSubscriberHandler()53 PullThrowSubscriberHandler::~PullThrowSubscriberHandler() {}
54
HandleFingerGestureDownEvent(std::shared_ptr<PointerEvent> touchEvent)55 void PullThrowSubscriberHandler::HandleFingerGestureDownEvent(std::shared_ptr<PointerEvent> touchEvent)
56 {
57 CALL_DEBUG_ENTER;
58 CHKPV(touchEvent);
59 if (!CheckFingerValidation(touchEvent)) {
60 return;
61 }
62 UpdateFingerPoisition(touchEvent);
63 MMI_HILOGI("PullThrow Check On Finger Down Event");
64 alreadyTouchDown_ = true;
65 StartFingerGesture();
66 }
67
HandleFingerGestureMoveEvent(std::shared_ptr<PointerEvent> touchEvent)68 void PullThrowSubscriberHandler::HandleFingerGestureMoveEvent(std::shared_ptr<PointerEvent> touchEvent)
69 {
70 CALL_DEBUG_ENTER;
71 CHKPV(touchEvent);
72 if (!CheckProgressValid(touchEvent)) {
73 return;
74 }
75 }
76
HandleFingerGesturePullMoveEvent(std::shared_ptr<PointerEvent> touchEvent)77 void PullThrowSubscriberHandler::HandleFingerGesturePullMoveEvent(std::shared_ptr<PointerEvent> touchEvent)
78 {
79 CALL_DEBUG_ENTER;
80 CHKPV(touchEvent);
81 if (!CheckProgressValid(touchEvent)) {
82 return;
83 }
84 if (gestureInProgress_ && alreadyTouchDown_) {
85 triggerTime_ = touchEvent->GetActionTime();
86 alreadyTouchDown_ = false;
87 UpdateFingerPoisition(touchEvent);
88 }
89 if (gestureInProgress_ && (touchEvent->GetActionTime() - triggerTime_ > WINDOW_TIME_INTERVAL)) {
90 triggerTime_ = touchEvent->GetActionTime();
91 UpdateFingerPoisition(touchEvent);
92 }
93 }
94
95
HandleFingerGesturePullUpEvent(std::shared_ptr<PointerEvent> touchEvent)96 void PullThrowSubscriberHandler::HandleFingerGesturePullUpEvent(std::shared_ptr<PointerEvent> touchEvent)
97 {
98 CALL_DEBUG_ENTER;
99 CHKPV(touchEvent);
100 MMI_HILOGI("PullThrow On PullUp Event");
101 if (!CheckProgressValid(touchEvent)) {
102 return;
103 }
104 // Update the last position point for calculating acceleration
105 int32_t id = touchEvent->GetPointerId();
106 PointerEvent::PointerItem item;
107 touchEvent->GetPointerItem(id, item);
108 UpdatePositionHistory(item.GetDisplayX(), item.GetDisplayY(), touchEvent->GetActionTime());
109 if (gestureInProgress_) {
110 MMI_HILOGI("PullThrow On gestureInProgress");
111 double endTime = touchEvent->GetActionTime();
112 // Calcultating distance
113 double dx = item.GetDisplayX() - fingerGesture_.touches[FIRST_TOUCH_FINGER].x;
114 double dy = item.GetDisplayY() - fingerGesture_.touches[FIRST_TOUCH_FINGER].y;
115 double distance = std::sqrt(dx * dx + dy * dy);
116 double deltaTime = (endTime - triggerTime_) / 1e3;
117 if (deltaTime <= 0) {
118 deltaTime = 1.0 / 1e3;
119 }
120 double speed = distance / deltaTime;
121 // provide a speed scale to improve success rate in spin area
122 if (item.GetDisplayY() > SPIN_UP_AREA_Y && item.GetDisplayY() < SPIN_DOWN_AREA_Y) {
123 speed = speed * SPEED_SCALE;
124 }
125 double throwAngle = atan2(dy, dx) * 180 / M_PI;
126 MMI_HILOGI("Throw speed: %{public}f, angle: %{public}f, dist: %{public}f", speed, throwAngle, distance);
127 // check sudden stop
128 bool hasSuddenStop = CheckSuddenStop();
129 if (hasSuddenStop) {
130 MMI_HILOGI("PullThrow detected sudden stop");
131 StopFingerGesture(touchEvent);
132 return;
133 }
134 // check pull throw condition: speed, distance, direction
135 if (speed > THRES_SPEED && distance > MIN_THRES_DIST && CheckThrowDirection(throwAngle, item.GetDisplayY())) {
136 touchEvent->SetPointerAction(PointerEvent::POINTER_ACTION_PULL_THROW);
137 touchEvent->SetThrowAngle(throwAngle);
138 touchEvent->SetThrowSpeed(speed);
139 MMI_HILOGI("PullThrow SUCCESS match gesture result");
140 } else {
141 MMI_HILOGI("PullThrow NO match gesture result");
142 }
143 }
144 StopFingerGesture(touchEvent);
145 }
146
HandleFingerGestureUpEvent(std::shared_ptr<PointerEvent> touchEvent)147 void PullThrowSubscriberHandler::HandleFingerGestureUpEvent(std::shared_ptr<PointerEvent> touchEvent)
148 {
149 CALL_DEBUG_ENTER;
150 CHKPV(touchEvent);
151 MMI_HILOGI("PullThrow Stop On Gesture Up Event");
152 StopFingerGesture(touchEvent);
153 }
154
UpdateFingerPoisition(std::shared_ptr<PointerEvent> touchEvent)155 void PullThrowSubscriberHandler::UpdateFingerPoisition(std::shared_ptr<PointerEvent> touchEvent)
156 {
157 CHKPV(touchEvent);
158 int32_t id = touchEvent->GetPointerId();
159 PointerEvent::PointerItem item;
160 touchEvent->GetPointerItem(id, item);
161 fingerGesture_.touches[FIRST_TOUCH_FINGER].id = id;
162 fingerGesture_.touches[FIRST_TOUCH_FINGER].x = item.GetDisplayX();
163 fingerGesture_.touches[FIRST_TOUCH_FINGER].y = item.GetDisplayY();
164
165 UpdatePositionHistory(item.GetDisplayX(), item.GetDisplayY(), touchEvent->GetActionTime());
166 }
167
CheckFingerValidation(std::shared_ptr<PointerEvent> touchEvent) const168 bool PullThrowSubscriberHandler::CheckFingerValidation(std::shared_ptr<PointerEvent> touchEvent) const
169 {
170 auto fingerCount = touchEvent->GetPointerIds().size();
171 if (fingerCount != static_cast<size_t>(ONE_FINGER)) {
172 MMI_HILOGD("PullThrow check cancel: The number of finger count is not 1");
173 return false;
174 }
175 return true;
176 }
177
CheckProgressValid(std::shared_ptr<PointerEvent> touchEvent)178 bool PullThrowSubscriberHandler::CheckProgressValid(std::shared_ptr<PointerEvent> touchEvent)
179 {
180 if (touchEvent->HasFlag(InputEvent::EVENT_FLAG_DISABLE_PULL_THROW)) {
181 StopFingerGesture(touchEvent);
182 return false;
183 }
184 if (gestureInProgress_ && !CheckFingerValidation(touchEvent)) {
185 StopFingerGesture(touchEvent);
186 return false;
187 }
188 return true;
189 }
190
CheckThrowDirection(double angle,int32_t posY)191 bool PullThrowSubscriberHandler::CheckThrowDirection(double angle, int32_t posY)
192 {
193 angle = (angle < NUM_EPSILON) ? angle + FULL_CIRCLE_DEGREES : angle;
194 if (posY < UP_SCREEN_AREA_Y && angle >= ANGLE_DOWN_MIN && angle < ANGLE_DOWN_MAX) {
195 return true;
196 }
197 if (posY > DOWN_SCREEN_AREA_Y && angle >= ANGLE_UP_MIN && angle < ANGLE_UP_MAX) {
198 return true;
199 }
200 return false;
201 }
202
CheckThrowAngleValid(double angle)203 bool PullThrowSubscriberHandler::CheckThrowAngleValid(double angle)
204 {
205 angle = (angle < NUM_EPSILON) ? angle + FULL_CIRCLE_DEGREES : angle;
206 if (angle >= ANGLE_DOWN_MIN && angle < ANGLE_DOWN_MAX) {
207 return true;
208 }
209 if (angle >= ANGLE_UP_MIN && angle < ANGLE_UP_MAX) {
210 return true;
211 }
212 return false;
213 }
214
StartFingerGesture()215 void PullThrowSubscriberHandler::StartFingerGesture()
216 {
217 CALL_DEBUG_ENTER;
218 gestureInProgress_ = true;
219 positionHistory_.clear();
220 }
221
StopFingerGesture(std::shared_ptr<PointerEvent> touchEvent)222 void PullThrowSubscriberHandler::StopFingerGesture(std::shared_ptr<PointerEvent> touchEvent)
223 {
224 CALL_DEBUG_ENTER;
225 gestureInProgress_ = false;
226 alreadyTouchDown_ = false;
227 triggerTime_ = touchEvent->GetActionTime();
228 positionHistory_.clear();
229 }
230
UpdatePositionHistory(double x,double y,double time)231 void PullThrowSubscriberHandler::UpdatePositionHistory(double x, double y, double time)
232 {
233 PositionRecord record;
234 record.x = x;
235 record.y = y;
236 record.time = time;
237
238 positionHistory_.push_back(record);
239 if (positionHistory_.size() > MAX_HISTORY_SIZE) {
240 positionHistory_.erase(positionHistory_.begin());
241 }
242 }
243
CheckSuddenStop() const244 bool PullThrowSubscriberHandler::CheckSuddenStop() const
245 {
246 if (positionHistory_.size() < MIN_HISTORY_SIZE) {
247 MMI_HILOGI("PullThrow position history size less than 3");
248 return false;
249 }
250
251 // 计算最近两段的速度
252 const auto& newest = positionHistory_.back();
253 const auto& middle = positionHistory_[positionHistory_.size() - 2];
254 const auto& oldest = positionHistory_[positionHistory_.size() - 3];
255
256 // 计算位移和时间差
257 double dx1 = middle.x - oldest.x;
258 double dy1 = middle.y - oldest.y;
259 double dt1 = (middle.time - oldest.time) / 1e3;
260
261 double dx2 = newest.x - middle.x;
262 double dy2 = newest.y - middle.y;
263 double dt2 = (newest.time - middle.time) / 1e3;
264
265 // 防止除以零
266 if (dt1 <= 0) dt1 = NUM_EPSILON;
267 if (dt2 <= 0) dt2 = NUM_EPSILON;
268
269 // 计算速度(矢量长度)
270 double speed1 = std::sqrt(dx1 * dx1 + dy1 * dy1) / dt1;
271 double speed2 = std::sqrt(dx2 * dx2 + dy2 * dy2) / dt2;
272
273 // 计算加速度(速度变化率)
274 double timeSpace = (dt1 + dt2) / 2;
275 if (timeSpace <= 0) timeSpace = NUM_EPSILON;
276 double acceleration = (speed2 - speed1) / timeSpace;
277
278 // 如果加速度为负且绝对值大于阈值,说明有急停动作
279 return (acceleration < MAX_DECELERATION);
280 }
281
282 } // namespace MMI
283 } // namespace OHOS
284