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