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