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#include "external_calls.h"
16#include "pointer_tracker.h"
17namespace OHOS::uitest {
18    void FingerTracker::HandleDownEvent(TouchEventInfo& event)
19    {
20        velocityTracker.UpdateTouchEvent(event, false);
21        fingerInfo.SetFirstTouchEventInfo(event);
22        fingerInfo.SetLastTouchEventInfo(event);
23    }
24
25    void FingerTracker::HandleMoveEvent(TouchEventInfo& event)
26    {
27        velocityTracker.UpdateTouchEvent(event, false);
28        fingerInfo.SetLastTouchEventInfo(event);
29    }
30
31    void FingerTracker::UpdatevelocityTracker(TouchEventInfo& event)
32    {
33        velocityTracker.UpdateTouchEvent(event, false);
34    }
35    void FingerTracker::HandleUpEvent(TouchEventInfo& event)
36    {
37        fingerInfo.SetLastTouchEventInfo(event);
38    }
39
40    void FingerTracker::BuildFingerInfo()
41    {
42        TouchEventInfo lastTouch = fingerInfo.GetLastTouchEventInfo();
43        TouchEventInfo firstTouch = fingerInfo.GetFirstTouchEventInfo();
44        fingerInfo.SetStepLength(velocityTracker.GetStepLength());
45        fingerInfo.SetVelocity(velocityTracker.GetMainAxisVelocity());
46        fingerInfo.SetDirection(Offset(lastTouch.x-firstTouch.x, lastTouch.y-firstTouch.y));
47    }
48
49    bool FingerTracker::IsRecentSpeedLimit(TouchEventInfo& touchEvent)
50    {
51        auto preEventTime = velocityTracker.GetPreTime(ONE);
52        double deltaT = touchEvent.durationSeconds * VelocityTracker::TIME_INDEX -
53                        preEventTime * VelocityTracker::TIME_INDEX;
54        auto preX = velocityTracker.GetPreX(ONE);
55        auto preY = velocityTracker.GetPreY(ONE);
56        auto speedX = (touchEvent.wx - preX) / deltaT;
57        auto speedY = (touchEvent.wy -  preY)/ deltaT;
58        auto speed = sqrt(speedX * speedX + speedY * speedY);
59        double curSpeed = touchEvent.wy > preY ? speed : -speed;
60        if (fabs(curSpeed) < 1e-6) {
61            return false;
62        }
63        auto acceleration = (curSpeed - preSpeed) / deltaT;
64        preSpeed = curSpeed;
65        return (acceleration > PointerTracker::RECENT_ACCELERAT && curSpeed > PointerTracker::RECENT_SPEED2) ||
66               (curSpeed > PointerTracker::RECENT_SPEED1 && deltaT > PointerTracker::RECENT_TIME);
67    }
68
69    // POINTER_TRACKER
70    void PointerTracker::HandleDownEvent(TouchEventInfo& event)
71    {
72        // 接受down事件时,若存在上次操作时间与本次down时间相差较大情况,说明上次操作接收情况异常,本次录制异常
73        if (fingerTrackers.size() != 0) {
74            TimeStamp thisTime = event.GetDownTimeStamp();
75            bool flag = false;
76            for (auto it = fingerTrackers.begin(); it != fingerTrackers.end(); it++) {
77                TimeStamp lastTime = it->second->GetVelocityTracker().GetLastTimePoint();
78                double  duration = (thisTime - lastTime).count();
79                if (duration > ERROR_POINTER && it->second != nullptr) {
80                    flag = true;
81                    delete it->second;
82                    it = fingerTrackers.erase(it);
83                    LOG_E("获取回调信息存在异常,请重新录制");
84                    std::cout << "获取回调信息存在异常,请重新录制" << std::endl;
85                    break;
86                }
87            }
88            if (flag) {
89                Resets();
90            }
91        }
92        if (fingerTrackers.size() == 0) {
93            firstTrackPoint_ = event;
94            InitJudgeChain();
95        }
96        FingerTracker* fTracker = new FingerTracker();
97        if (fTracker == nullptr) {
98            LOG_E("Failedf to new FingerTracker");
99        } else {
100            fTracker->HandleDownEvent(event);
101            fingerTrackers.insert({event.downTime, fTracker});
102            currentFingerNum++;
103        }
104    }
105
106    void PointerTracker::HandleMoveEvent(TouchEventInfo& event)
107    {
108        if (fingerTrackers.count(event.downTime)) {
109            if (pointerTypeJudgChain_.size() > 1) {
110                auto judgeFunction = pointerTypeJudgMap_.find(pointerTypeJudgChain_[0])->second;
111                judgeFunction(event);
112            }
113            FingerTracker* ftracker = fingerTrackers.find(event.downTime)->second;
114            ftracker->HandleMoveEvent(event);
115        }
116    }
117
118    void PointerTracker::HandleUpEvent(TouchEventInfo& event)
119    {
120        if (fingerTrackers.count(event.downTime)) {
121            // 第一个抬起的手指,记录手指总数
122            if (maxFingerNum == 0 && fingerTrackers.size() != 0) {
123                maxFingerNum = fingerTrackers.size();
124                isUpStage = true;
125            }
126            // 抬起判断
127            bool flag = false;
128            fingerTrackers.find(event.downTime)->second->UpdatevelocityTracker(event);
129            while (pointerTypeJudgChain_.size() > 1 && !flag) {
130                auto judgeFunction = pointerTypeJudgMap_.find(pointerTypeJudgChain_[0])->second;
131                flag = judgeFunction(event);
132            }
133            fingerTrackers.find(event.downTime)->second->HandleUpEvent(event);
134            fingerTrackers.find(event.downTime)->second->BuildFingerInfo();
135            currentFingerNum--;
136            // 最后一个抬起的手指,快照+复位
137            if (currentFingerNum == 0) {
138                snapshootPointerInfo = BuildPointerInfo();
139                isNeedWrite = true;
140                if (snapshootPointerInfo.GetTouchOpt() == OP_CLICK &&
141                    isLastClickInTracker && GetInterVal() < INTERVAL_THRESHOLD) { // doubleClick
142                    snapshootPointerInfo.SetTouchOpt(OP_DOUBLE_CLICK);
143                    isLastClickInTracker = false;
144                } else if (snapshootPointerInfo.GetTouchOpt() == OP_CLICK) { // click
145                    lastClickInfo = snapshootPointerInfo;
146                    isLastClickInTracker = true;
147                }
148                maxFingerNum = 0;
149                isUpStage = false;
150                ClearFingerTrackersValues();
151            }
152        }
153    }
154
155    void PointerTracker::HandleMoveEvent(TouchEventInfo& event, TouchOpt touchOpt)
156    {
157        pointerTypeJudgChain_.clear();
158        pointerTypeJudgChain_ = {touchOpt};
159        HandleMoveEvent(event);
160    }
161
162    void PointerTracker::HandleUpEvent(TouchEventInfo& event, TouchOpt touchOpt)
163    {
164        pointerTypeJudgChain_.clear();
165        pointerTypeJudgChain_ = {touchOpt};
166        HandleUpEvent(event);
167    }
168
169    void PointerTracker::ClearFingerTrackersValues()
170    {
171        for (auto it = fingerTrackers.begin(); it != fingerTrackers.end(); it++) {
172            if (it->second != nullptr) {
173                delete it->second;
174            }
175        }
176        fingerTrackers.clear();
177    }
178
179    void PointerTracker::InitJudgeChain()
180    {
181        pointerTypeJudgChain_.clear();
182        pointerTypeJudgChain_ = {
183            OP_CLICK, OP_LONG_CLICK, OP_DRAG, OP_RECENT, OP_HOME, OP_RETURN, OP_SWIPE, OP_FLING
184        };
185        isStartRecent = false;
186        if (pointerTypeJudgMap_.size() == 0) {
187            pointerTypeJudgMap_.emplace(std::make_pair(OP_CLICK,
188                function<bool(TouchEventInfo&)>(bind(&PointerTracker::IsClick, this, placeholders::_1))));
189            pointerTypeJudgMap_.emplace(std::make_pair(OP_LONG_CLICK,
190                function<bool(TouchEventInfo&)>(bind(&PointerTracker::IsLongClick, this, placeholders::_1))));
191            pointerTypeJudgMap_.emplace(std::make_pair(OP_DRAG,
192                function<bool(TouchEventInfo&)>(bind(&PointerTracker::IsDrag, this, placeholders::_1))));
193            pointerTypeJudgMap_.emplace(std::make_pair(OP_RETURN,
194                function<bool(TouchEventInfo&)>(bind(&PointerTracker::IsBack, this, placeholders::_1))));
195            pointerTypeJudgMap_.emplace(std::make_pair(OP_SWIPE,
196                function<bool(TouchEventInfo&)>(bind(&PointerTracker::IsSwip, this, placeholders::_1))));
197            pointerTypeJudgMap_.emplace(std::make_pair(OP_RECENT,
198                function<bool(TouchEventInfo&)>(bind(&PointerTracker::IsRecent, this, placeholders::_1))));
199            pointerTypeJudgMap_.emplace(std::make_pair(OP_FLING,
200                function<bool(TouchEventInfo&)>(bind(&PointerTracker::IsFling, this, placeholders::_1))));
201            pointerTypeJudgMap_.emplace(std::make_pair(OP_HOME,
202                function<bool(TouchEventInfo&)>(bind(&PointerTracker::IsHome, this, placeholders::_1))));
203        }
204    }
205
206    bool PointerTracker::IsClick(TouchEventInfo& touchEvent) // click(back)
207    {
208        // 时间 > DURATIOIN_THRESHOLD && move > MAX_THRESHOLD
209        int moveDistance = fingerTrackers.find(touchEvent.downTime)->second->GetMoveDistance();
210        if (touchEvent.durationSeconds > DURATIOIN_THRESHOLD || moveDistance > MAX_THRESHOLD) {
211            // 不满足点击操作,删除OP_CLICK
212            RemoveTypeJudge(pointerTypeJudgChain_, OP_CLICK);
213            return false;
214        }
215        return true;
216    }
217
218    bool PointerTracker::IsLongClick(TouchEventInfo& touchEvent)
219    {
220        // 先时间 > DURATIOIN_THRESHOLD,不满足则删除LONCLICK && DRAG
221        if (touchEvent.durationSeconds < DURATIOIN_THRESHOLD) {
222            RemoveTypeJudge(pointerTypeJudgChain_, OP_LONG_CLICK, OP_DRAG);
223            return false;
224        }
225        // 初始时间长,排除滑动类操作
226        RemoveTypeJudge(pointerTypeJudgChain_, OP_SWIPE, OP_FLING, OP_HOME, OP_RECENT);
227        // 后 move > MAX_THRESHOLD ,若不满足却通过时间判断则为DRAG
228        int moveDistance = fingerTrackers.find(touchEvent.downTime)->second->GetMoveDistance();
229        if (moveDistance > MAX_THRESHOLD) {
230            RemoveTypeJudge(pointerTypeJudgChain_, OP_LONG_CLICK);
231            return false;
232        }
233        return true;
234    }
235
236    bool PointerTracker::IsDrag(TouchEventInfo& touchEvent)
237    {
238        // 其实LongClick已经判断过了
239        // 时间 > DURATIOIN_THRESHOLD && move > MAX_THRESHOLD
240        auto ftracker = fingerTrackers.find(touchEvent.downTime)->second;
241        int moveDistance = ftracker->GetMoveDistance();
242        if (touchEvent.durationSeconds < DURATIOIN_THRESHOLD || moveDistance < MAX_THRESHOLD) {
243            RemoveTypeJudge(pointerTypeJudgChain_, OP_DRAG);
244            return false;
245        }
246        return true;
247    }
248
249    // bool PinchJudge(TouchEventInfo& touchEvent)
250
251    bool PointerTracker::IsRecent(TouchEventInfo& touchEvent)
252    {
253        // 起点位置判断
254        auto ftracker = fingerTrackers.find(touchEvent.downTime)->second;
255        TouchEventInfo startEvent = ftracker->GetFingerInfo().GetFirstTouchEventInfo();
256        if (startEvent.y <= windowBounds.bottom_ * NAVI_THRE_D) {
257            RemoveTypeJudge(pointerTypeJudgChain_, OP_RECENT, OP_HOME);
258            return false;
259        }
260        if (isStartRecent) {
261            return true;
262        } else {
263            // 滑动位移判断
264            bool isDistance = (double)(windowBounds.bottom_ - touchEvent.y) / windowBounds.bottom_ >= RECENT_DISTANCE;
265            // 速度判断
266            bool isRecentSpeed = ftracker -> IsRecentSpeedLimit(touchEvent);
267            if (isDistance && isRecentSpeed) {
268                isStartRecent = true;
269                return true;
270            } else if (isUpStage) {
271                RemoveTypeJudge(pointerTypeJudgChain_, OP_RECENT);
272                return false;
273            }
274            return true;
275        }
276    }
277
278    bool PointerTracker::IsHome(TouchEventInfo& touchEvent)
279    {
280        // 起点位置已判断
281        // 滑动位移判断
282        bool isDistance = (double)(windowBounds.bottom_ - touchEvent.y) / windowBounds.bottom_ >= HOME_DISTANCE;
283        if (isDistance) {
284            return true;
285        } else if (isUpStage) {
286            RemoveTypeJudge(pointerTypeJudgChain_, OP_HOME);
287            return false;
288        }
289        return true;
290    }
291
292    bool PointerTracker::IsBack(TouchEventInfo& touchEvent)
293    {
294        // 滑动类只有起手才能判断
295        if (!isUpStage) {
296            return true;
297        }
298        auto ftracker = fingerTrackers.find(touchEvent.downTime)->second;
299        TouchEventInfo startEvent = ftracker->GetFingerInfo().GetFirstTouchEventInfo();
300        VelocityTracker vTracker = ftracker->GetVelocityTracker();
301        if (startEvent.x - windowBounds.left_ <= NAVI_THRE_D &&
302            ftracker->GetMoveDistance() >= NAVI_VERTI_THRE_V) {
303            RemoveTypeJudge(pointerTypeJudgChain_, OP_SWIPE, OP_RECENT, OP_FLING, OP_HOME);
304            return true;
305        }
306        RemoveTypeJudge(pointerTypeJudgChain_, OP_RETURN);
307        return false;
308    }
309
310    bool PointerTracker::IsSwip(TouchEventInfo& touchEvent) // swip
311    {
312        // 滑动类只有起手才能判断
313        if (!isUpStage) {
314            return true;
315        }
316        auto ftracker = fingerTrackers.find(touchEvent.downTime)->second;
317        double mainVelocity = ftracker->GetVelocityTracker().GetMainAxisVelocity();
318        // 离手v < FLING_THRESHOLD
319        if (mainVelocity >= FLING_THRESHOLD) {
320            RemoveTypeJudge(pointerTypeJudgChain_, OP_SWIPE);
321            return false;
322        }
323        return true;
324    }
325
326    bool PointerTracker::IsFling(TouchEventInfo& touchEvent) // fling
327    {
328        // SWIP判断过离手速度
329        return true;
330    }
331
332    PointerInfo PointerTracker::BuildPointerInfo()
333    {
334        PointerInfo pointerInfo;
335        pointerInfo.SetTouchOpt(pointerTypeJudgChain_[0]);
336        pointerInfo.SetFingerNumber(maxFingerNum);
337        pointerInfo.SetFirstTrackPoint(firstTrackPoint_);
338        for (auto it = fingerTrackers.begin(); it != fingerTrackers.end(); it++) {
339            pointerInfo.AddFingerInfo(it->second->GetFingerInfo());
340        }
341        auto fastTouch = pointerInfo.GetFingerInfoList()[0].GetLastTouchEventInfo();
342        auto lastTouch = pointerInfo.GetFingerInfoList()[fingerTrackers.size()-1].GetLastTouchEventInfo();
343        pointerInfo.SetDuration((lastTouch.GetActionTimeStamp() - fastTouch.GetDownTimeStamp()).count());
344        if (pointerInfo.GetTouchOpt() == OP_CLICK || pointerInfo.GetTouchOpt() == OP_LONG_CLICK) {
345            std::vector<std::string> names = GetFrontAbility();
346            pointerInfo.SetBundleName(names[0]);
347            pointerInfo.SetAbilityName(names[1]);
348        }
349        if (pointerInfo.GetTouchOpt() == OP_DRAG ||
350            pointerInfo.GetTouchOpt() == OP_SWIPE ||
351            pointerInfo.GetTouchOpt() == OP_FLING) {
352            // 平均方向->向量相加
353            Offset avgDirection;
354            int addStepLength = 0;
355            double addVelocity = 0.0;
356            for (auto it = fingerTrackers.begin(); it != fingerTrackers.end(); it++) {
357                avgDirection += it->second->GetFingerInfo().GetDirection();
358                addStepLength += it->second->GetVelocityTracker().GetStepLength();
359                addVelocity += it->second->GetFingerInfo().GetVelocity();
360            }
361            pointerInfo.SetAvgDirection(avgDirection);
362            pointerInfo.SetAvgStepLength(addStepLength/fingerTrackers.size());
363            double avgVelocity = addVelocity/fingerTrackers.size();
364            pointerInfo.SetAvgVelocity(avgVelocity);
365        }
366        return pointerInfo;
367    }
368
369    // cout
370    std::string PointerTracker::WriteData(PointerInfo pointerInfo, shared_ptr<mutex> &cout_lock)
371    {
372        auto out = pointerInfo.WriteWindowData();
373        std::lock_guard<mutex> guard(*cout_lock);
374        std::cout << out << std::endl;
375        return out;
376    }
377
378    // record.csv
379    nlohmann::json PointerTracker::WriteData(PointerInfo pointerInfo, ofstream& outFile, shared_ptr<mutex> &csv_lock)
380    {
381        auto out = pointerInfo.WriteData();
382        std::lock_guard<mutex> guard(*csv_lock);
383        if (outFile.is_open()) {
384            outFile << out.dump() << std::endl;
385        }
386        return out;
387    }
388}