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