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"
17 namespace OHOS::uitest {
HandleDownEvent(TouchEventInfo& event)18     void FingerTracker::HandleDownEvent(TouchEventInfo& event)
19     {
20         velocityTracker.UpdateTouchEvent(event, false);
21         fingerInfo.SetFirstTouchEventInfo(event);
22         fingerInfo.SetLastTouchEventInfo(event);
23     }
24 
HandleMoveEvent(TouchEventInfo& event)25     void FingerTracker::HandleMoveEvent(TouchEventInfo& event)
26     {
27         velocityTracker.UpdateTouchEvent(event, false);
28         fingerInfo.SetLastTouchEventInfo(event);
29     }
30 
UpdatevelocityTracker(TouchEventInfo& event)31     void FingerTracker::UpdatevelocityTracker(TouchEventInfo& event)
32     {
33         velocityTracker.UpdateTouchEvent(event, false);
34     }
HandleUpEvent(TouchEventInfo& event)35     void FingerTracker::HandleUpEvent(TouchEventInfo& event)
36     {
37         fingerInfo.SetLastTouchEventInfo(event);
38     }
39 
BuildFingerInfo()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 
IsRecentSpeedLimit(TouchEventInfo& touchEvent)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
HandleDownEvent(TouchEventInfo& event)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 
HandleMoveEvent(TouchEventInfo& event)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 
HandleUpEvent(TouchEventInfo& event)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 
HandleMoveEvent(TouchEventInfo& event, TouchOpt touchOpt)155     void PointerTracker::HandleMoveEvent(TouchEventInfo& event, TouchOpt touchOpt)
156     {
157         pointerTypeJudgChain_.clear();
158         pointerTypeJudgChain_ = {touchOpt};
159         HandleMoveEvent(event);
160     }
161 
HandleUpEvent(TouchEventInfo& event, TouchOpt touchOpt)162     void PointerTracker::HandleUpEvent(TouchEventInfo& event, TouchOpt touchOpt)
163     {
164         pointerTypeJudgChain_.clear();
165         pointerTypeJudgChain_ = {touchOpt};
166         HandleUpEvent(event);
167     }
168 
ClearFingerTrackersValues()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 
InitJudgeChain()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 
IsClick(TouchEventInfo& touchEvent)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 
IsLongClick(TouchEventInfo& touchEvent)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 
IsDrag(TouchEventInfo& touchEvent)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 
IsRecent(TouchEventInfo& touchEvent)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 
IsHome(TouchEventInfo& touchEvent)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 
IsBack(TouchEventInfo& touchEvent)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 
IsSwip(TouchEventInfo& touchEvent)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 
IsFling(TouchEventInfo& touchEvent)326     bool PointerTracker::IsFling(TouchEventInfo& touchEvent) // fling
327     {
328         // SWIP判断过离手速度
329         return true;
330     }
331 
BuildPointerInfo()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
WriteData(PointerInfo pointerInfo, shared_ptr<mutex> &cout_lock)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
WriteData(PointerInfo pointerInfo, ofstream& outFile, shared_ptr<mutex> &csv_lock)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 }