1 /*
2  * Copyright (c) 2021-2024 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 "base/ressched/ressched_report.h"
17 
18 #define LIKELY(x) __builtin_expect(!!(x), 1)
19 
20 namespace OHOS::Ace {
21 namespace Ressched {
22 constexpr uint32_t RES_TYPE_CLICK_RECOGNIZE = 9;
23 constexpr uint32_t RES_TYPE_PUSH_PAGE       = 10;
24 constexpr uint32_t RES_TYPE_SLIDE           = 11;
25 constexpr uint32_t RES_TYPE_POP_PAGE        = 28;
26 constexpr uint32_t RES_TYPE_WEB_GESTURE     = 29;
27 constexpr uint32_t RES_TYPE_LOAD_PAGE       = 34;
28 #ifdef FFRT_EXISTS
29 constexpr uint32_t RES_TYPE_LONG_FRAME     = 71;
30 #endif
31 constexpr int32_t TOUCH_DOWN_EVENT          = 1;
32 constexpr int32_t CLICK_EVENT               = 2;
33 constexpr int32_t TOUCH_UP_EVENT            = 3;
34 constexpr int32_t TOUCH_PULL_UP_EVENT = 4;
35 constexpr int32_t SLIDE_OFF_EVENT = 0;
36 constexpr int32_t SLIDE_DETECTING = 2;
37 constexpr int32_t AUTO_PLAY_ON_EVENT = 5;
38 constexpr int32_t AUTO_PLAY_OFF_EVENT = 6;
39 constexpr int32_t PUSH_PAGE_START_EVENT = 0;
40 constexpr int32_t PUSH_PAGE_COMPLETE_EVENT = 1;
41 constexpr int32_t POP_PAGE_EVENT = 0;
42 #ifdef FFRT_EXISTS
43 constexpr int32_t LONG_FRAME_START_EVENT = 0;
44 constexpr int32_t LONG_FRAME_END_EVENT = 1;
45 #endif
46 constexpr char NAME[] = "name";
47 constexpr char PID[] = "pid";
48 constexpr char UID[] = "uid";
49 constexpr char BUNDLE_NAME[] = "bundleName";
50 constexpr char ABILITY_NAME[] = "abilityName";
51 constexpr char CLICK[] = "click";
52 constexpr char PUSH_PAGE[] = "push_page";
53 constexpr char POP_PAGE[] = "pop_page";
54 constexpr char AUTO_PLAY_ON[] = "auto_play_on";
55 constexpr char AUTO_PLAY_OFF[] = "auto_play_off";
56 constexpr char SLIDE_OFF[] = "slide_off";
57 constexpr char TOUCH[] = "touch";
58 constexpr char WEB_GESTURE[] = "web_gesture";
59 constexpr char LOAD_PAGE[] = "load_page";
60 constexpr char UP_SPEED_KEY[] = "up_speed";
61 #ifdef FFRT_EXISTS
62 constexpr char LONG_FRAME_START[] = "long_frame_start";
63 constexpr char LONG_FRAME_END[] = "long_frame_end";
64 #endif
65 
LoadAceApplicationContext(std::unordered_map<std::string,std::string> & payload)66 void LoadAceApplicationContext(std::unordered_map<std::string, std::string>& payload)
67 {
68     auto& aceApplicationInfo = AceApplicationInfo::GetInstance();
69     payload[PID] = std::to_string(aceApplicationInfo.GetPid());
70     payload[UID] = std::to_string(aceApplicationInfo.GetUid());
71     payload[BUNDLE_NAME] = aceApplicationInfo.GetPackageName();
72     payload[ABILITY_NAME] = aceApplicationInfo.GetAbilityName();
73 }
74 }
75 
76 using namespace Ressched;
77 
GetInstance()78 ResSchedReport& ResSchedReport::GetInstance()
79 {
80     static ResSchedReport instance;
81     return instance;
82 }
83 
ResSchedDataReport(const char * name,const std::unordered_map<std::string,std::string> & param)84 void ResSchedReport::ResSchedDataReport(const char* name, const std::unordered_map<std::string, std::string>& param)
85 {
86     std::unordered_map<std::string, std::string> payload = param;
87     payload[Ressched::NAME] = name;
88     if (!reportDataFunc_) {
89         reportDataFunc_ = LoadReportDataFunc();
90     }
91     if (!reportDataFunc_) {
92         return;
93     }
94     static std::unordered_map<std::string, std::function<void(std::unordered_map<std::string, std::string>&)>>
95         functionMap = {
96             { CLICK,
97                 [this](std::unordered_map<std::string, std::string>& payload) {
98                     reportDataFunc_(RES_TYPE_CLICK_RECOGNIZE, CLICK_EVENT, payload);
99                 }
100             },
101             { AUTO_PLAY_ON,
102                 [this](std::unordered_map<std::string, std::string>& payload) {
103                     reportDataFunc_(RES_TYPE_SLIDE, AUTO_PLAY_ON_EVENT, payload);
104                 }
105             },
106             { AUTO_PLAY_OFF,
107                 [this](std::unordered_map<std::string, std::string>& payload) {
108                     reportDataFunc_(RES_TYPE_SLIDE, AUTO_PLAY_OFF_EVENT, payload);
109                 }
110             },
111             { SLIDE_OFF,
112                 [this](std::unordered_map<std::string, std::string>& payload) {
113                     reportDataFunc_(RES_TYPE_SLIDE, SLIDE_OFF_EVENT, payload);
114                 }
115             },
116             { POP_PAGE,
117                 [this](std::unordered_map<std::string, std::string>& payload) {
118                     LoadAceApplicationContext(payload);
119                     reportDataFunc_(RES_TYPE_POP_PAGE, POP_PAGE_EVENT, payload);
120                 }
121             },
122             { WEB_GESTURE,
123                 [this](std::unordered_map<std::string, std::string>& payload) {
124                     reportDataFunc_(RES_TYPE_WEB_GESTURE, 0, payload);
125                 }
126             },
127 #ifdef FFRT_EXISTS
128             { LONG_FRAME_START,
129                 [this](std::unordered_map<std::string, std::string>& payload) {
130                     LoadAceApplicationContext(payload);
131                     reportDataFunc_(RES_TYPE_LONG_FRAME, LONG_FRAME_START_EVENT, payload);
132                 }
133             },
134             { LONG_FRAME_END,
135                 [this](std::unordered_map<std::string, std::string>& payload) {
136                     LoadAceApplicationContext(payload);
137                     reportDataFunc_(RES_TYPE_LONG_FRAME, LONG_FRAME_END_EVENT, payload);
138                 }
139             },
140 #endif
141         };
142     auto it = functionMap.find(name);
143     if (it == functionMap.end()) {
144         return;
145     }
146     it->second(payload);
147 }
148 
ResSchedDataReport(uint32_t resType,int32_t value,const std::unordered_map<std::string,std::string> & payload)149 void ResSchedReport::ResSchedDataReport(uint32_t resType, int32_t value,
150     const std::unordered_map<std::string, std::string>& payload)
151 {
152     if (reportDataFunc_ == nullptr) {
153         reportDataFunc_ = LoadReportDataFunc();
154     }
155     if (reportDataFunc_ != nullptr) {
156         reportDataFunc_(resType, value, payload);
157     }
158 }
159 
OnTouchEvent(const TouchEvent & touchEvent)160 void ResSchedReport::OnTouchEvent(const TouchEvent& touchEvent)
161 {
162     switch (touchEvent.type) {
163         case TouchType::DOWN:
164             HandleTouchDown(touchEvent);
165             break;
166         case TouchType::UP:
167             HandleTouchUp(touchEvent);
168             break;
169         case TouchType::MOVE:
170             HandleTouchMove(touchEvent);
171             break;
172         case TouchType::CANCEL:
173             HandleTouchCancel(touchEvent);
174             break;
175         case TouchType::PULL_DOWN:
176             HandleTouchPullDown(touchEvent);
177             break;
178         case TouchType::PULL_UP:
179             HandleTouchPullUp(touchEvent);
180             break;
181         case TouchType::PULL_MOVE:
182             HandleTouchPullMove(touchEvent);
183             break;
184         default:
185             break;
186     }
187 }
188 
RecordTouchEvent(const TouchEvent & touchEvent,bool enforce)189 void ResSchedReport::RecordTouchEvent(const TouchEvent& touchEvent, bool enforce)
190 {
191     if (enforce) {
192         lastTouchEvent_ = touchEvent;
193         curTouchEvent_ = touchEvent;
194     } else if (curTouchEvent_.GetOffset() != touchEvent.GetOffset()) {
195         lastTouchEvent_ = curTouchEvent_;
196         curTouchEvent_ = touchEvent;
197     }
198 }
199 
HandleTouchDown(const TouchEvent & touchEvent)200 void ResSchedReport::HandleTouchDown(const TouchEvent& touchEvent)
201 {
202     std::unordered_map<std::string, std::string> payload;
203     payload[Ressched::NAME] = TOUCH;
204     ResSchedDataReport(RES_TYPE_CLICK_RECOGNIZE, TOUCH_DOWN_EVENT, payload);
205     RecordTouchEvent(touchEvent, true);
206 }
207 
HandleTouchUp(const TouchEvent & touchEvent)208 void ResSchedReport::HandleTouchUp(const TouchEvent& touchEvent)
209 {
210     std::unordered_map<std::string, std::string> payload;
211     RecordTouchEvent(touchEvent);
212     payload[Ressched::NAME] = TOUCH;
213     payload[UP_SPEED_KEY] = std::to_string(GetUpVelocity(lastTouchEvent_, curTouchEvent_));
214     ResSchedDataReport(RES_TYPE_CLICK_RECOGNIZE, TOUCH_UP_EVENT, payload);
215     isInSilde = false;
216     averageDistance_.Reset();
217 }
218 
HandleTouchMove(const TouchEvent & touchEvent)219 void ResSchedReport::HandleTouchMove(const TouchEvent& touchEvent)
220 {
221     RecordTouchEvent(touchEvent);
222     averageDistance_ += curTouchEvent_.GetOffset() - lastTouchEvent_.GetOffset();
223     if (averageDistance_.GetDistance() >= ResDefine::JUDGE_DISTANCE && !isInSilde) {
224         std::unordered_map<std::string, std::string> payload;
225         LoadAceApplicationContext(payload);
226         ResSchedDataReport(RES_TYPE_SLIDE, SLIDE_DETECTING, payload);
227         isInSilde = true;
228     }
229 }
230 
HandleTouchCancel(const TouchEvent & touchEvent)231 void ResSchedReport::HandleTouchCancel(const TouchEvent& touchEvent)
232 {
233     isInSilde = false;
234     averageDistance_.Reset();
235 }
236 
HandleTouchPullDown(const TouchEvent & touchEvent)237 void ResSchedReport::HandleTouchPullDown(const TouchEvent& touchEvent)
238 {
239     RecordTouchEvent(touchEvent, true);
240 }
241 
HandleTouchPullUp(const TouchEvent & touchEvent)242 void ResSchedReport::HandleTouchPullUp(const TouchEvent& touchEvent)
243 {
244     std::unordered_map<std::string, std::string> payload;
245     payload[Ressched::NAME] = TOUCH;
246     ResSchedDataReport(RES_TYPE_CLICK_RECOGNIZE, TOUCH_PULL_UP_EVENT, payload);
247     averageDistance_.Reset();
248 }
249 
HandleTouchPullMove(const TouchEvent & touchEvent)250 void ResSchedReport::HandleTouchPullMove(const TouchEvent& touchEvent)
251 {
252     if (!isInSilde) {
253         std::unordered_map<std::string, std::string> payload;
254         LoadAceApplicationContext(payload);
255         ResSchedDataReport(RES_TYPE_SLIDE, SLIDE_DETECTING, payload);
256         isInSilde = true;
257     }
258     RecordTouchEvent(touchEvent);
259 }
260 
GetUpVelocity(const TouchEvent & lastMoveInfo,const TouchEvent & upEventInfo)261 double ResSchedReport::GetUpVelocity(const TouchEvent& lastMoveInfo,
262     const TouchEvent& upEventInfo)
263 {
264     double distance = sqrt(pow(lastMoveInfo.x - upEventInfo.x, SQUARE) + pow(lastMoveInfo.y - upEventInfo.y, SQUARE));
265     int64_t time = std::chrono::duration_cast<std::chrono::milliseconds>(upEventInfo.GetTimeStamp() -
266         lastMoveInfo.GetTimeStamp()).count();
267     if (time <= 0) {
268         return 0.0f;
269     }
270     return distance * dpi_ / static_cast<double>(time); //unit: pixel/ms
271 }
272 
LoadPageEvent(int32_t value)273 void ResSchedReport::LoadPageEvent(int32_t value)
274 {
275     if (LIKELY(value == ResDefine::LOAD_PAGE_COMPLETE_EVENT && loadPageOn_ == false)) {
276         return;
277     } else if (value == ResDefine::LOAD_PAGE_COMPLETE_EVENT && loadPageOn_ == true) {
278         loadPageOn_ = false;
279     } else if (value == ResDefine::LOAD_PAGE_START_EVENT) {
280         loadPageOn_ = true;
281     }
282 
283     std::unordered_map<std::string, std::string> payload;
284     payload[Ressched::NAME] = LOAD_PAGE;
285     LoadAceApplicationContext(payload);
286     ResSchedDataReport(RES_TYPE_LOAD_PAGE, value, payload);
287 }
288 
ResSchedReportScope(const std::string & name,const std::unordered_map<std::string,std::string> & param)289 ResSchedReportScope::ResSchedReportScope(const std::string& name,
290     const std::unordered_map<std::string, std::string>& param) : name_(name), payload_(param)
291 {
292     name_ = name;
293     payload_[Ressched::NAME] = name;
294     LoadAceApplicationContext(payload_);
295     if (name_ == PUSH_PAGE) {
296         ResSchedReport::GetInstance().ResSchedDataReport(RES_TYPE_PUSH_PAGE, PUSH_PAGE_START_EVENT, payload_);
297         ResSchedReport::GetInstance().LoadPageEvent(ResDefine::LOAD_PAGE_START_EVENT);
298     }
299 }
300 
~ResSchedReportScope()301 ResSchedReportScope::~ResSchedReportScope()
302 {
303     if (name_ == PUSH_PAGE) {
304         ResSchedReport::GetInstance().ResSchedDataReport(RES_TYPE_PUSH_PAGE, PUSH_PAGE_COMPLETE_EVENT, payload_);
305     }
306 }
307 } // namespace OHOS::Ace