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 
16 #include "core/common/event_dump.h"
17 #include "core/pipeline_ng/pipeline_context.h"
18 
19 namespace OHOS::Ace::NG {
20 namespace {
21 constexpr size_t MAX_EVENT_TREE_RECORD_CNT = 5;
22 constexpr size_t MAX_FRAME_NODE_CNT = 256;
23 constexpr int32_t MAX_EVENT_TREE_TOUCH_DOWN_CNT = 10;
24 constexpr int32_t MAX_EVENT_TREE_TOUCH_POINT_CNT = 20;
25 constexpr int32_t MAX_EVENT_TREE_AXIS_UPDATE_CNT = 20;
26 constexpr int32_t MAX_EVENT_TREE_AXIS_CNT = 20;
27 constexpr int32_t MAX_EVENT_TREE_GESTURE_CNT = 100;
28 } // end of namespace
29 
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth) const30 void FrameNodeSnapshot::Dump(std::list<std::pair<int32_t, std::string>>& dumpList, int32_t depth) const
31 {
32     std::stringstream oss;
33     oss << "nodeId: " << nodeId << ", "
34         << "parentId: " << parentNodeId << ", "
35         << "tag: " << tag << ", ";
36     if (!comId.empty()) {
37         oss << "comId: " << comId << ", ";
38     }
39     oss << "monopolizeEvents: " << monopolizeEvents << ", "
40         << "isHit: " << isHit << ", "
41         << "hitTestMode: " << hitTestMode << ", ";
42 #ifndef IS_RELEASE_VERSION
43     oss << "responseRegion: ";
44     for (const auto& rect : responseRegionList) {
45         oss << rect.ToString().c_str();
46     }
47 #endif
48     dumpList.emplace_back(std::make_pair(depth, oss.str()));
49 }
50 
TouchPointSnapshot(const TouchEvent & event)51 TouchPointSnapshot::TouchPointSnapshot(const TouchEvent& event)
52 {
53     id = event.id;
54     point = OffsetF(event.x, event.y);
55     screenPoint = OffsetF(event.screenX, event.screenY);
56     type = event.type;
57     timestamp = GetCurrentTimestamp();
58     isInjected = event.isInjected;
59     auto pipeline = PipelineContext::GetCurrentContext();
60     CHECK_NULL_VOID(pipeline);
61     auto eventManager = pipeline->GetEventManager();
62     CHECK_NULL_VOID(eventManager);
63     downFingerIds = eventManager->GetDownFingerIds();
64 }
65 
AxisSnapshot(const AxisEvent & event)66 AxisSnapshot::AxisSnapshot(const AxisEvent& event)
67 {
68     id = event.id;
69     point = OffsetF(event.x, event.y);
70     screenPoint = OffsetF(event.screenX, event.screenY);
71     action = event.action;
72     timestamp = GetCurrentTimestamp();
73     isInjected = event.isInjected;
74 }
75 
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth) const76 void TouchPointSnapshot::Dump(std::list<std::pair<int32_t, std::string>>& dumpList, int32_t depth) const
77 {
78     std::string downFingerIdStr = "";
79     for (const auto& iter : downFingerIds) {
80         downFingerIdStr += std::to_string(iter.first) + " ";
81     }
82     std::stringstream oss;
83 #ifdef IS_RELEASE_VERSION
84     oss << "id: " << id << ", "
85         << "type: " << GestureSnapshot::TransTouchType(type) << ", "
86         << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
87         << "isInjected: " << isInjected << ", "
88         << "downFingerIds: " << downFingerIdStr;
89 #else
90     oss << "id: " << id << ", "
91         << "point: " << point.ToString() << ", "
92         << "screenPoint: " << screenPoint.ToString() << ", "
93         << "type: " << GestureSnapshot::TransTouchType(type) << ", "
94         << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
95         << "isInjected: " << isInjected << ", "
96         << "downFingerIds: " << downFingerIdStr;
97 #endif
98     dumpList.emplace_back(std::make_pair(depth, oss.str()));
99 }
100 
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth) const101 void AxisSnapshot::Dump(std::list<std::pair<int32_t, std::string>>& dumpList, int32_t depth) const
102 {
103     std::stringstream oss;
104     std::string strAction = std::string("Node");
105     switch (action) {
106         case AxisAction::BEGIN:
107             strAction = std::string("BEGIN");
108             break;
109         case AxisAction::UPDATE:
110             strAction = std::string("UPDATE");
111             break;
112         case AxisAction::END:
113             strAction = std::string("END");
114             break;
115         default:
116             LOGW("AxisAction: Unknown AxisAction action %{public}d", action);
117             break;
118     }
119 #ifdef IS_RELEASE_VERSION
120     oss << "id: " << id << ", "
121         << "action: " << strAction << ", "
122         << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
123         << "isInjected: " << isInjected;
124 #else
125     oss << "id: " << id << ", "
126         << "point: " << point.ToString() << ", "
127         << "screenPoint: " << screenPoint.ToString() << ", "
128         << "action: " << strAction << ", "
129         << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
130         << "isInjected: " << isInjected;
131 #endif
132     dumpList.emplace_back(std::make_pair(depth, oss.str()));
133 }
134 
AddAxis(const AxisEvent & event)135 void EventTreeRecord::AddAxis(const AxisEvent& event)
136 {
137     if (!eventTreeList.empty() && eventTreeList.back().axis.size() > MAX_EVENT_TREE_AXIS_CNT) {
138         eventTreeList.pop_back();
139         TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
140             "EventTreeList last record axis size is over limit! Last record is cleaned.");
141     }
142     if (!eventTreeList.empty() && event.action == Ace::AxisAction::BEGIN &&
143         eventTreeList.back().updateAxisIds_.count(event.id) > 0) {
144         eventTreeList.pop_back();
145         TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
146             "EventTreeList last record receive BEGIN event twice. Last record is cleaned.");
147     }
148     AxisAction action = event.action;
149     if (action == Ace::AxisAction::BEGIN) {
150         if (eventTreeList.empty() || eventTreeList.back().axisUpdateCount <= 0 ||
151             eventTreeList.back().axisUpdateCount >= MAX_EVENT_TREE_AXIS_UPDATE_CNT) {
152             eventTreeList.emplace_back(EventTree());
153             if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
154                 eventTreeList.erase(eventTreeList.begin());
155             }
156         }
157         eventTreeList.back().axisUpdateCount++;
158         eventTreeList.back().updateAxisIds_.insert(event.id);
159     }
160     if (eventTreeList.empty()) {
161         return;
162     }
163     if (action == AxisAction::END || action == AxisAction::CANCEL) {
164         eventTreeList.back().axisUpdateCount--;
165         eventTreeList.back().updateAxisIds_.erase(event.id);
166     }
167     eventTreeList.back().axis.emplace_back(AxisSnapshot(event));
168 }
169 
AddTouchPoint(const TouchEvent & event)170 void EventTreeRecord::AddTouchPoint(const TouchEvent& event)
171 {
172     if (!eventTreeList.empty()) {
173         if (eventTreeList.back().touchPoints.size() > MAX_EVENT_TREE_TOUCH_POINT_CNT) {
174             eventTreeList.pop_back();
175             TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
176                 "EventTreeList last record touchPoint size is over limit! Last record is cleaned.");
177         }
178         if (!eventTreeList.empty() && event.type == Ace::TouchType::DOWN &&
179             eventTreeList.back().downFingerIds_.count(event.id) > 0) {
180             eventTreeList.pop_back();
181             TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
182                 "EventTreeList last record receive DOWN event twice. Last record is cleaned.");
183         }
184     }
185     TouchType type = event.type;
186     if (type == Ace::TouchType::DOWN) {
187         // multi fingers touch down will be in one tree
188         if (eventTreeList.empty() || eventTreeList.back().touchDownCount <= 0 ||
189             eventTreeList.back().touchDownCount >= MAX_EVENT_TREE_TOUCH_DOWN_CNT) {
190             eventTreeList.emplace_back(EventTree());
191             if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
192                 eventTreeList.erase(eventTreeList.begin());
193             }
194         }
195         eventTreeList.back().touchDownCount++;
196         eventTreeList.back().downFingerIds_.insert(event.id);
197     }
198 
199     if (eventTreeList.empty()) {
200         return;
201     }
202 
203     if (type == TouchType::UP || type == TouchType::CANCEL || type == TouchType::PULL_UP ||
204         type == TouchType::PULL_OUT_WINDOW) {
205         eventTreeList.back().touchDownCount--;
206         eventTreeList.back().downFingerIds_.erase(event.id);
207     }
208     eventTreeList.back().touchPoints.emplace_back(TouchPointSnapshot(event));
209 }
210 
AddFrameNodeSnapshot(FrameNodeSnapshot && node)211 void EventTreeRecord::AddFrameNodeSnapshot(FrameNodeSnapshot&& node)
212 {
213     if (eventTreeList.empty()) {
214         return;
215     }
216     if (eventTreeList.back().hitTestTree.size() < MAX_FRAME_NODE_CNT) {
217         bool isInList = false;
218         for (auto& iter : eventTreeList.back().hitTestTree) {
219             if (iter.nodeId == node.nodeId) {
220                 isInList = true;
221                 break;
222             }
223         }
224         if (isInList) {
225             return;
226         }
227         eventTreeList.back().hitTestTree.emplace_back(node);
228     }
229 }
230 
AddGestureSnapshot(int32_t finger,RefPtr<GestureSnapshot> && gesture)231 void EventTreeRecord::AddGestureSnapshot(int32_t finger, RefPtr<GestureSnapshot>&& gesture)
232 {
233     if (eventTreeList.empty()) {
234         return;
235     }
236     if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
237         eventTreeList.clear();
238         TAG_LOGW(AceLogTag::ACE_INPUTTRACKING, "EventTreeList size is over MAX, clean event tree.");
239         return;
240     }
241     auto& gestureTree = eventTreeList.back().gestureTree;
242     auto& gestureMap = eventTreeList.back().gestureMap;
243     if (gestureMap.size() > MAX_EVENT_TREE_GESTURE_CNT) {
244         eventTreeList.clear();
245         TAG_LOGW(AceLogTag::ACE_INPUTTRACKING, "GestureMap size is over MAX, clean event tree.");
246         return;
247     }
248     gestureMap[gesture->id] = gesture;
249     gestureTree[finger].emplace_back(gesture);
250 }
251 
AddGestureProcedure(uint64_t id,const std::string & procedure,const std::string & extraInfo,const std::string & state,const std::string & disposal,int64_t timestamp)252 void EventTreeRecord::AddGestureProcedure(uint64_t id, const std::string& procedure, const std::string& extraInfo,
253     const std::string& state, const std::string& disposal, int64_t timestamp)
254 {
255     if (eventTreeList.empty()) {
256         return;
257     }
258     auto& gestureMap = eventTreeList.back().gestureMap;
259     auto iter = gestureMap.find(id);
260     if (iter == gestureMap.end()) {
261         return;
262     }
263     // TouchEventActuator don't record move
264     if (iter->second->type == "TouchEventActuator") {
265         return;
266     }
267     iter->second->AddProcedure(procedure, extraInfo, state, disposal, timestamp);
268 }
269 
AddGestureProcedure(uint64_t id,const TouchEvent & point,const std::string & extraInfo,const std::string & state,const std::string & disposal,int64_t timestamp)270 void EventTreeRecord::AddGestureProcedure(uint64_t id, const TouchEvent& point, const std::string& extraInfo,
271     const std::string& state, const std::string& disposal, int64_t timestamp)
272 {
273     if (eventTreeList.empty()) {
274         return;
275     }
276     auto& gestureMap = eventTreeList.back().gestureMap;
277     auto iter = gestureMap.find(id);
278     if (iter == gestureMap.end()) {
279         return;
280     }
281 
282     if ((point.type == TouchType::MOVE || point.type == TouchType::PULL_MOVE) &&
283         !iter->second->CheckNeedAddMove(state, disposal)) {
284         return;
285     }
286     std::string procedure = std::string("Handle").append(GestureSnapshot::TransTouchType(point.type));
287     iter->second->AddProcedure(procedure, extraInfo, state, disposal, timestamp);
288 }
289 
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth,int32_t startNumber) const290 void EventTreeRecord::Dump(std::list<std::pair<int32_t, std::string>>& dumpList,
291     int32_t depth, int32_t startNumber) const
292 {
293     int32_t index = 0;
294     int32_t listDepth = depth + 1;
295     int32_t detailDepth = listDepth + 1;
296     for (auto& tree : eventTreeList) {
297         if (index < startNumber) {
298             index++;
299             continue;
300         }
301         std::string header = std::to_string(index).append(": event tree =>");
302 
303         // dump needful touch points:
304         dumpList.emplace_back(std::make_pair(depth, header));
305         dumpList.emplace_back(std::make_pair(listDepth, "touch points:"));
306         for (auto& item : tree.touchPoints) {
307             item.Dump(dumpList, detailDepth);
308         }
309 
310         // dump needful axis:
311         dumpList.emplace_back(std::make_pair(listDepth, "axis:"));
312         for (auto& item : tree.axis) {
313             item.Dump(dumpList, detailDepth);
314         }
315 
316         // dump hit test frame nodes:
317         dumpList.emplace_back(std::make_pair(listDepth, "hittest:"));
318         for (auto& item : tree.hitTestTree) {
319             item.Dump(dumpList, detailDepth);
320         }
321 
322         // dump gesture event and procedure:
323         dumpList.emplace_back(std::make_pair(listDepth, "event procedures:"));
324         for (auto iter = tree.gestureTree.begin(); iter != tree.gestureTree.end(); ++iter) {
325             dumpList.emplace_back(std::make_pair(detailDepth,
326                 std::string("finger:").append(std::to_string(iter->first))));
327             for (const auto& item : iter->second) {
328                 item->Dump(dumpList, detailDepth + 1);
329             }
330         }
331         ++index;
332     }
333 }
334 
Dump(std::unique_ptr<JsonValue> & json) const335 void AxisSnapshot::Dump(std::unique_ptr<JsonValue>& json) const
336 {
337     json->Put("point", point.ToString().c_str());
338     json->Put("screenPoint", screenPoint.ToString().c_str());
339     switch (action) {
340         case AxisAction::BEGIN:
341             json->Put("action", "BEGIN");
342             break;
343         case AxisAction::UPDATE:
344             json->Put("action", "UPDATE");
345             break;
346         case AxisAction::END:
347             json->Put("action", "END");
348             break;
349         default:
350             LOGW("AxisAction: Unknown AxisAction action %{public}d", action);
351             break;
352     }
353     json->Put("timestamp", ConvertTimestampToStr(timestamp).c_str());
354     json->Put("isInjected", isInjected);
355 }
356 
BuildAxis(std::list<AxisSnapshot> axis,std::unique_ptr<JsonValue> & json) const357 void EventTreeRecord::BuildAxis(
358     std::list<AxisSnapshot> axis, std::unique_ptr<JsonValue>& json) const
359 {
360     std::unique_ptr<JsonValue> axisEvent = JsonUtil::CreateArray(true);
361     for (auto& item : axis) {
362         std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
363         item.Dump(child);
364         axisEvent->Put(child);
365     }
366     json->Put("axis", axisEvent);
367 }
368 } // end of namespace
369