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 "core/common/recorder/event_recorder.h"
16
17 #include "base/json/json_util.h"
18 #include "base/log/log_wrapper.h"
19 #include "base/utils/string_utils.h"
20 #include "base/utils/time_util.h"
21 #include "core/common/container.h"
22 #include "core/common/recorder/event_controller.h"
23 #include "core/common/recorder/node_data_cache.h"
24
25 namespace OHOS::Ace::Recorder {
26 constexpr char IGNORE_WINDOW_NAME[] = "$HA_FLOAT_WINDOW$";
27
EventParamsBuilder()28 EventParamsBuilder::EventParamsBuilder()
29 {
30 params_ = std::make_shared<std::unordered_map<std::string, std::string>>();
31 }
32
SetEventType(EventType eventType)33 EventParamsBuilder& EventParamsBuilder::SetEventType(EventType eventType)
34 {
35 eventType_ = eventType;
36 return *this;
37 }
38
SetId(const std::string & id)39 EventParamsBuilder& EventParamsBuilder::SetId(const std::string& id)
40 {
41 if (!id.empty()) {
42 params_->emplace(KEY_ID, id);
43 }
44 return *this;
45 }
46
SetType(const std::string & type)47 EventParamsBuilder& EventParamsBuilder::SetType(const std::string& type)
48 {
49 params_->emplace(KEY_TYPE, type);
50 return *this;
51 }
52
SetDescription(const std::string & desc)53 EventParamsBuilder& EventParamsBuilder::SetDescription(const std::string& desc)
54 {
55 if (!desc.empty()) {
56 params_->emplace(KEY_DESCRIPTION, desc);
57 }
58 return *this;
59 }
60
SetNavDst(const std::string & dstName)61 EventParamsBuilder& EventParamsBuilder::SetNavDst(const std::string& dstName)
62 {
63 if (!dstName.empty()) {
64 params_->emplace(KEY_NAV_DST, dstName);
65 }
66 return *this;
67 }
68
SetPageUrl(const std::string & pageUrl)69 EventParamsBuilder& EventParamsBuilder::SetPageUrl(const std::string& pageUrl)
70 {
71 if (!pageUrl.empty()) {
72 params_->emplace(KEY_PAGE, pageUrl);
73 }
74 return *this;
75 }
76
SetText(const std::string & value)77 EventParamsBuilder& EventParamsBuilder::SetText(const std::string& value)
78 {
79 if (!value.empty()) {
80 params_->emplace(KEY_TEXT, value);
81 }
82 return *this;
83 }
84
SetChecked(bool value)85 EventParamsBuilder& EventParamsBuilder::SetChecked(bool value)
86 {
87 std::string strVal = value ? "true" : "false";
88 params_->emplace(KEY_CHECKED, strVal);
89 return *this;
90 }
91
SetIndex(int value)92 EventParamsBuilder& EventParamsBuilder::SetIndex(int value)
93 {
94 params_->emplace(KEY_INDEX, std::to_string(value));
95 return *this;
96 }
97
SetTextArray(const std::vector<std::string> & value)98 EventParamsBuilder& EventParamsBuilder::SetTextArray(const std::vector<std::string>& value)
99 {
100 auto jsonArray = JsonUtil::CreateArray(true);
101 for (size_t i = 0; i < value.size(); i++) {
102 jsonArray->Put(std::to_string(i).c_str(), value.at(i).c_str());
103 }
104 params_->emplace(KEY_TEXT_ARRAY, jsonArray->ToString());
105 return *this;
106 }
107
SetExtra(const std::string & key,const std::string & value)108 EventParamsBuilder& EventParamsBuilder::SetExtra(const std::string& key, const std::string& value)
109 {
110 if (!key.empty() && !value.empty()) {
111 params_->emplace(key, value);
112 }
113 return *this;
114 }
115
build()116 std::shared_ptr<std::unordered_map<std::string, std::string>> EventParamsBuilder::build()
117 {
118 return params_;
119 }
120
GetEventType() const121 EventType EventParamsBuilder::GetEventType() const
122 {
123 return eventType_;
124 }
125
GetText() const126 std::string EventParamsBuilder::GetText() const
127 {
128 auto iter = params_->find(KEY_TEXT);
129 if (iter != params_->end()) {
130 return iter->second;
131 }
132 return "";
133 }
134
ToString() const135 std::string EventParamsBuilder::ToString() const
136 {
137 std::stringstream ss;
138 ss << "{";
139 if (eventType_ != EventType::INVALID) {
140 ss << "eventType:" << eventType_ << ", ";
141 }
142 for (auto&& it : *params_) {
143 ss << it.first << ":" << it.second << ", ";
144 }
145 ss << "}";
146 return ss.str();
147 }
148
MapToString(const std::shared_ptr<std::unordered_map<std::string,std::string>> & input)149 std::string MapToString(const std::shared_ptr<std::unordered_map<std::string, std::string>>& input)
150 {
151 if (!input) {
152 return "";
153 }
154 std::stringstream ss;
155 ss << "{";
156 for (auto it = input->begin(); it != input->end(); it++) {
157 ss << it->first << ":" << it->second << ", ";
158 }
159 ss << "}";
160 return ss.str();
161 }
162
Get()163 EventRecorder& EventRecorder::Get()
164 {
165 static EventRecorder eventRecorder;
166 return eventRecorder;
167 }
168
EventRecorder()169 EventRecorder::EventRecorder() {}
170
UpdateEventSwitch(const EventSwitch & eventSwitch)171 void EventRecorder::UpdateEventSwitch(const EventSwitch& eventSwitch)
172 {
173 eventSwitch_ = eventSwitch;
174 }
175
IsPageRecordEnable() const176 bool EventRecorder::IsPageRecordEnable() const
177 {
178 return pageEnable_ && eventSwitch_.pageEnable;
179 }
180
IsExposureRecordEnable() const181 bool EventRecorder::IsExposureRecordEnable() const
182 {
183 return exposureEnable_ && eventSwitch_.exposureEnable;
184 }
185
IsComponentRecordEnable() const186 bool EventRecorder::IsComponentRecordEnable() const
187 {
188 return componentEnable_ && eventSwitch_.componentEnable;
189 }
190
SetContainerInfo(const std::string & windowName,int32_t id,bool foreground)191 void EventRecorder::SetContainerInfo(const std::string& windowName, int32_t id, bool foreground)
192 {
193 if (windowName == IGNORE_WINDOW_NAME) {
194 return;
195 }
196 if (foreground) {
197 containerId_ = id;
198 containerCount_++;
199 } else {
200 containerCount_--;
201 }
202 if (containerCount_ <= 0) {
203 containerCount_ = 0;
204 containerId_ = -1;
205 }
206 }
207
SetFocusContainerInfo(const std::string & windowName,int32_t id)208 void EventRecorder::SetFocusContainerInfo(const std::string& windowName, int32_t id)
209 {
210 if (windowName == IGNORE_WINDOW_NAME) {
211 return;
212 }
213 focusContainerId_ = id;
214 }
215
GetContainerId()216 int32_t EventRecorder::GetContainerId()
217 {
218 if (containerId_ == -1) {
219 return -1;
220 }
221 return focusContainerId_;
222 }
223
GetPageUrl()224 const std::string& EventRecorder::GetPageUrl()
225 {
226 if (pageUrl_.empty()) {
227 pageUrl_ = GetCurrentPageUrl();
228 }
229 return pageUrl_;
230 }
231
GetNavDstName() const232 const std::string& EventRecorder::GetNavDstName() const
233 {
234 return navDstName_;
235 }
236
OnPageShow(const std::string & pageUrl,const std::string & param)237 void EventRecorder::OnPageShow(const std::string& pageUrl, const std::string& param)
238 {
239 pageUrl_ = pageUrl;
240 NodeDataCache::Get().OnPageShow(pageUrl);
241 Recorder::EventParamsBuilder builder;
242 builder.SetType(std::to_string(PageEventType::ROUTER_PAGE))
243 .SetText(pageUrl)
244 .SetExtra(Recorder::KEY_PAGE_PARAM, param);
245 EventController::Get().NotifyEvent(
246 EventCategory::CATEGORY_PAGE, static_cast<int32_t>(EventType::PAGE_SHOW), std::move(builder.build()));
247 }
248
OnPageHide(const std::string & pageUrl,const int64_t duration)249 void EventRecorder::OnPageHide(const std::string& pageUrl, const int64_t duration)
250 {
251 Recorder::EventParamsBuilder builder;
252 builder.SetType(std::to_string(PageEventType::ROUTER_PAGE))
253 .SetText(pageUrl)
254 .SetExtra(KEY_DURATION, std::to_string(duration));
255 EventController::Get().NotifyEvent(
256 EventCategory::CATEGORY_PAGE, static_cast<int32_t>(EventType::PAGE_HIDE), std::move(builder.build()));
257 }
258
OnClick(EventParamsBuilder && builder)259 void EventRecorder::OnClick(EventParamsBuilder&& builder)
260 {
261 if (!taskExecutor_) {
262 auto container = Container::Current();
263 CHECK_NULL_VOID(container);
264 taskExecutor_ = container->GetTaskExecutor();
265 }
266 CHECK_NULL_VOID(taskExecutor_);
267 builder.SetPageUrl(GetPageUrl());
268 builder.SetNavDst(navDstName_);
269 auto params = builder.build();
270 taskExecutor_->PostTask(
271 [taskExecutor = taskExecutor_, params]() {
272 EventController::Get().NotifyEvent(
273 EventCategory::CATEGORY_COMPONENT, static_cast<int32_t>(EventType::CLICK), std::move(params));
274 },
275 TaskExecutor::TaskType::UI);
276 }
277
OnChange(EventParamsBuilder && builder)278 void EventRecorder::OnChange(EventParamsBuilder&& builder)
279 {
280 builder.SetPageUrl(GetPageUrl());
281 builder.SetNavDst(navDstName_);
282 auto params = builder.build();
283 EventController::Get().NotifyEvent(
284 EventCategory::CATEGORY_COMPONENT, static_cast<int32_t>(EventType::CHANGE), std::move(params));
285 }
286
OnEvent(EventParamsBuilder && builder)287 void EventRecorder::OnEvent(EventParamsBuilder&& builder)
288 {
289 builder.SetPageUrl(GetPageUrl());
290 builder.SetNavDst(navDstName_);
291 auto eventType = builder.GetEventType();
292 auto params = builder.build();
293 EventController::Get().NotifyEvent(
294 EventCategory::CATEGORY_COMPONENT, static_cast<int32_t>(eventType), std::move(params));
295 }
296
OnNavDstShow(EventParamsBuilder && builder)297 void EventRecorder::OnNavDstShow(EventParamsBuilder&& builder)
298 {
299 navDstName_ = builder.GetText();
300 navShowTime_ = GetCurrentTimestamp();
301 builder.SetPageUrl(GetPageUrl());
302 builder.SetType(std::to_string(PageEventType::NAV_PAGE));
303 auto params = builder.build();
304 EventController::Get().NotifyEvent(
305 EventCategory::CATEGORY_PAGE, static_cast<int32_t>(EventType::PAGE_SHOW), std::move(params));
306 }
307
OnNavDstHide(EventParamsBuilder && builder)308 void EventRecorder::OnNavDstHide(EventParamsBuilder&& builder)
309 {
310 if (builder.GetText() == navDstName_) {
311 navDstName_ = "";
312 if (navShowTime_ > 0) {
313 int64_t duration = GetCurrentTimestamp() - navShowTime_;
314 builder.SetExtra(KEY_DURATION, std::to_string(duration));
315 navShowTime_ = 0;
316 }
317 }
318 builder.SetPageUrl(GetPageUrl());
319 builder.SetType(std::to_string(PageEventType::NAV_PAGE));
320 auto params = builder.build();
321 EventController::Get().NotifyEvent(
322 EventCategory::CATEGORY_PAGE, static_cast<int32_t>(EventType::PAGE_HIDE), std::move(params));
323 }
324
OnExposure(EventParamsBuilder && builder)325 void EventRecorder::OnExposure(EventParamsBuilder&& builder)
326 {
327 auto params = builder.build();
328 EventController::Get().NotifyEvent(
329 EventCategory::CATEGORY_EXPOSURE, static_cast<int32_t>(EventType::EXPOSURE), std::move(params));
330 }
331 } // namespace OHOS::Ace::Recorder
332