• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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