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     isInTouch_ = true;
207 }
208 
HandleTouchUp(const TouchEvent& touchEvent)209 void ResSchedReport::HandleTouchUp(const TouchEvent& touchEvent)
210 {
211     std::unordered_map<std::string, std::string> payload;
212     RecordTouchEvent(touchEvent);
213     payload[Ressched::NAME] = TOUCH;
214     payload[UP_SPEED_KEY] = std::to_string(GetUpVelocity(lastTouchEvent_, curTouchEvent_));
215     ResSchedDataReport(RES_TYPE_CLICK_RECOGNIZE, TOUCH_UP_EVENT, payload);
216     isInSlide_ = false;
217     isInTouch_ = false;
218     averageDistance_.Reset();
219 }
220 
HandleTouchMove(const TouchEvent& touchEvent)221 void ResSchedReport::HandleTouchMove(const TouchEvent& touchEvent)
222 {
223     RecordTouchEvent(touchEvent);
224     averageDistance_ += curTouchEvent_.GetOffset() - lastTouchEvent_.GetOffset();
225     if (averageDistance_.GetDistance() >= ResDefine::JUDGE_DISTANCE &&
226         !isInSlide_ && isInTouch_) {
227         std::unordered_map<std::string, std::string> payload;
228         LoadAceApplicationContext(payload);
229         ResSchedDataReport(RES_TYPE_SLIDE, SLIDE_DETECTING, payload);
230         isInSlide_ = true;
231     }
232 }
233 
HandleTouchCancel(const TouchEvent& touchEvent)234 void ResSchedReport::HandleTouchCancel(const TouchEvent& touchEvent)
235 {
236     isInSlide_ = false;
237     isInTouch_ = false;
238     averageDistance_.Reset();
239 }
240 
HandleTouchPullDown(const TouchEvent& touchEvent)241 void ResSchedReport::HandleTouchPullDown(const TouchEvent& touchEvent)
242 {
243     RecordTouchEvent(touchEvent, true);
244     isInTouch_ = true;
245 }
246 
HandleTouchPullUp(const TouchEvent& touchEvent)247 void ResSchedReport::HandleTouchPullUp(const TouchEvent& touchEvent)
248 {
249     std::unordered_map<std::string, std::string> payload;
250     payload[Ressched::NAME] = TOUCH;
251     ResSchedDataReport(RES_TYPE_CLICK_RECOGNIZE, TOUCH_PULL_UP_EVENT, payload);
252     averageDistance_.Reset();
253     isInTouch_ = false;
254 }
255 
HandleTouchPullMove(const TouchEvent& touchEvent)256 void ResSchedReport::HandleTouchPullMove(const TouchEvent& touchEvent)
257 {
258     if (!isInSlide_) {
259         std::unordered_map<std::string, std::string> payload;
260         LoadAceApplicationContext(payload);
261         ResSchedDataReport(RES_TYPE_SLIDE, SLIDE_DETECTING, payload);
262         isInSlide_ = true;
263     }
264     RecordTouchEvent(touchEvent);
265 }
266 
GetUpVelocity(const TouchEvent& lastMoveInfo, const TouchEvent& upEventInfo)267 double ResSchedReport::GetUpVelocity(const TouchEvent& lastMoveInfo,
268     const TouchEvent& upEventInfo)
269 {
270     double distance = sqrt(pow(lastMoveInfo.x - upEventInfo.x, SQUARE) + pow(lastMoveInfo.y - upEventInfo.y, SQUARE));
271     int64_t time = std::chrono::duration_cast<std::chrono::milliseconds>(upEventInfo.GetTimeStamp() -
272         lastMoveInfo.GetTimeStamp()).count();
273     if (time <= 0) {
274         return 0.0f;
275     }
276     return distance * dpi_ / static_cast<double>(time); //unit: pixel/ms
277 }
278 
LoadPageEvent(int32_t value)279 void ResSchedReport::LoadPageEvent(int32_t value)
280 {
281     if (LIKELY(value == ResDefine::LOAD_PAGE_COMPLETE_EVENT && loadPageOn_ == false)) {
282         return;
283     } else if (value == ResDefine::LOAD_PAGE_COMPLETE_EVENT && loadPageOn_ == true) {
284         loadPageOn_ = false;
285     } else if (value == ResDefine::LOAD_PAGE_START_EVENT) {
286         loadPageOn_ = true;
287     }
288 
289     std::unordered_map<std::string, std::string> payload;
290     payload[Ressched::NAME] = LOAD_PAGE;
291     LoadAceApplicationContext(payload);
292     ResSchedDataReport(RES_TYPE_LOAD_PAGE, value, payload);
293 }
294 
ResSchedReportScope(const std::string& name, const std::unordered_map<std::string, std::string>& param)295 ResSchedReportScope::ResSchedReportScope(const std::string& name,
296     const std::unordered_map<std::string, std::string>& param) : name_(name), payload_(param)
297 {
298     name_ = name;
299     payload_[Ressched::NAME] = name;
300     LoadAceApplicationContext(payload_);
301     if (name_ == PUSH_PAGE) {
302         ResSchedReport::GetInstance().ResSchedDataReport(RES_TYPE_PUSH_PAGE, PUSH_PAGE_START_EVENT, payload_);
303         ResSchedReport::GetInstance().LoadPageEvent(ResDefine::LOAD_PAGE_START_EVENT);
304     }
305 }
306 
~ResSchedReportScope()307 ResSchedReportScope::~ResSchedReportScope()
308 {
309     if (name_ == PUSH_PAGE) {
310         ResSchedReport::GetInstance().ResSchedDataReport(RES_TYPE_PUSH_PAGE, PUSH_PAGE_COMPLETE_EVENT, payload_);
311     }
312 }
313 } // namespace OHOS::Ace
314