1 // Copyright 2011 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "include/activity_replay.h"
6
7 #include <limits.h>
8 #include <set>
9 #include <string>
10
11 #include <gtest/gtest.h>
12 #include <json/reader.h>
13 #include <json/writer.h>
14
15 #include "include/logging.h"
16 #include "include/prop_registry.h"
17 #include "include/unittest_util.h"
18 #include "include/util.h"
19
20 using std::endl;
21 using std::set;
22 using std::string;
23
24 namespace {
25
26 // Helper to std::visit with lambdas.
27 template <typename... V>
28 struct Visitor : V... {
29 using V::operator()...;
30 };
31 // Explicit deduction guide (not needed as of C++20).
32 template <typename... V>
33 Visitor(V...) -> Visitor<V...>;
34
35 } // namespace
36
37 namespace gestures {
38
ActivityReplay(PropRegistry * prop_reg)39 ActivityReplay::ActivityReplay(PropRegistry* prop_reg)
40 : log_(nullptr), prop_reg_(prop_reg) {}
41
Parse(const string & data)42 bool ActivityReplay::Parse(const string& data) {
43 std::set<string> emptyset;
44 return Parse(data, emptyset);
45 }
46
Parse(const string & data,const std::set<string> & honor_props)47 bool ActivityReplay::Parse(const string& data,
48 const std::set<string>& honor_props) {
49 log_.Clear();
50 names_.clear();
51
52 string error_msg;
53 Json::Value root;
54 {
55 Json::CharReaderBuilder builder;
56 std::unique_ptr<Json::CharReader> const reader(builder.newCharReader());
57 const char * const data_str = data.c_str();
58
59 if (!reader->parse(data_str, data_str + data.size(),
60 &root, &error_msg)) { // root modified in parse()
61 Err("Parse failed: %s", error_msg.c_str());
62 return false;
63 }
64 }
65 if (root.type() != Json::objectValue) {
66 Err("Root type is %d, but expected %d (dictionary)",
67 root.type(), Json::objectValue);
68 return false;
69 }
70 // Get and apply user-configurable properties
71 Json::Value props_dict =
72 root.get(ActivityLog::kKeyProperties, Json::Value());
73 if (root.isMember(ActivityLog::kKeyProperties) &&
74 !ParseProperties(props_dict, honor_props)) {
75 Err("Unable to parse properties.");
76 return false;
77 }
78 // Get and apply hardware properties
79 if (!root.isMember(ActivityLog::kKeyHardwarePropRoot)) {
80 Err("Unable to get hwprops dict.");
81 return false;
82 }
83 Json::Value hwprops_dict =
84 root.get(ActivityLog::kKeyHardwarePropRoot, Json::Value());
85 if (!ParseHardwareProperties(hwprops_dict, &hwprops_))
86 return false;
87 log_.SetHardwareProperties(hwprops_);
88 Json::Value entries = root.get(ActivityLog::kKeyRoot, Json::Value());
89 char next_layer_path[PATH_MAX];
90 snprintf(next_layer_path, sizeof(next_layer_path), "%s.%s",
91 ActivityLog::kKeyNext, ActivityLog::kKeyRoot);
92 if (!root.isMember(ActivityLog::kKeyRoot)) {
93 Err("Unable to get list of entries from root.");
94 return false;
95 }
96 if (root.isMember(next_layer_path)) {
97 Json::Value next_layer_entries = root[next_layer_path];
98 if (entries.size() < next_layer_entries.size())
99 entries = next_layer_entries;
100 }
101
102 for (size_t i = 0; i < entries.size(); ++i) {
103 Json::Value entry = entries.get(i, Json::Value());
104 if (!entries.isValidIndex(i)) {
105 Err("Invalid entry at index %zu", i);
106 return false;
107 }
108 if (!ParseEntry(entry))
109 return false;
110 }
111 return true;
112 }
113
ParseProperties(const Json::Value & dict,const std::set<string> & honor_props)114 bool ActivityReplay::ParseProperties(const Json::Value& dict,
115 const std::set<string>& honor_props) {
116 if (!prop_reg_)
117 return true;
118 ::set<Property*> props = prop_reg_->props();
119 for (::set<Property*>::const_iterator it = props.begin(), e = props.end();
120 it != e; ++it) {
121 const char* key = (*it)->name();
122
123 // TODO(clchiou): This is just a emporary workaround for property changes.
124 // I will work out a solution for this kind of changes.
125 if (!strcmp(key, "Compute Surface Area from Pressure") ||
126 !strcmp(key, "Touchpad Device Output Bias on X-Axis") ||
127 !strcmp(key, "Touchpad Device Output Bias on Y-Axis")) {
128 continue;
129 }
130
131 if (!honor_props.empty() && !SetContainsValue(honor_props, string(key)))
132 continue;
133 if (!dict.isMember(key)) {
134 Err("Log doesn't have value for property %s", key);
135 continue;
136 }
137 const Json::Value& value = dict[key];
138 if (!(*it)->SetValue(value)) {
139 Err("Unable to restore value for property %s", key);
140 return false;
141 }
142 }
143 return true;
144 }
145
146 #define PARSE_HP(obj, key, IsTypeFn, KeyFn, var, VarType, required) \
147 do { \
148 if (!obj.isMember(key) || !obj[key].IsTypeFn()) { \
149 Err("Parse failed for key %s", key); \
150 if (required) \
151 return false; \
152 } \
153 var = obj[key].KeyFn(); \
154 } while (0)
155
ParseHardwareProperties(const Json::Value & obj,HardwareProperties * out_props)156 bool ActivityReplay::ParseHardwareProperties(const Json::Value& obj,
157 HardwareProperties* out_props) {
158 HardwareProperties props;
159 PARSE_HP(obj, ActivityLog::kKeyHardwarePropLeft, isDouble, asDouble,
160 props.left, float, true);
161 PARSE_HP(obj, ActivityLog::kKeyHardwarePropTop, isDouble, asDouble,
162 props.top, float, true);
163 PARSE_HP(obj, ActivityLog::kKeyHardwarePropRight, isDouble, asDouble,
164 props.right, float, true);
165 PARSE_HP(obj, ActivityLog::kKeyHardwarePropBottom, isDouble, asDouble,
166 props.bottom, float, true);
167 PARSE_HP(obj, ActivityLog::kKeyHardwarePropXResolution, isDouble, asDouble,
168 props.res_x, float, true);
169 PARSE_HP(obj, ActivityLog::kKeyHardwarePropYResolution, isDouble, asDouble,
170 props.res_y, float, true);
171 PARSE_HP(obj, ActivityLog::kKeyHardwarePropOrientationMinimum,
172 isDouble, asDouble, props.orientation_minimum, float, false);
173 PARSE_HP(obj, ActivityLog::kKeyHardwarePropOrientationMaximum,
174 isDouble, asDouble, props.orientation_maximum, float, false);
175 PARSE_HP(obj, ActivityLog::kKeyHardwarePropMaxFingerCount, isInt, asUInt,
176 props.max_finger_cnt, unsigned short, true);
177 PARSE_HP(obj, ActivityLog::kKeyHardwarePropMaxTouchCount, isInt, asUInt,
178 props.max_touch_cnt, unsigned short, true);
179 PARSE_HP(obj, ActivityLog::kKeyHardwarePropSupportsT5R2, isBool, asBool,
180 props.supports_t5r2, bool, true);
181 PARSE_HP(obj, ActivityLog::kKeyHardwarePropSemiMt,isBool, asBool,
182 props.support_semi_mt, bool, true);
183 PARSE_HP(obj, ActivityLog::kKeyHardwarePropIsButtonPad,isBool, asBool,
184 props.is_button_pad, bool, true);
185 PARSE_HP(obj, ActivityLog::kKeyHardwarePropHasWheel,isBool, asBool,
186 props.has_wheel, bool, true);
187 *out_props = props;
188 return true;
189 }
190
191 #undef PARSE_HP
192
ParseEntry(const Json::Value & entry)193 bool ActivityReplay::ParseEntry(const Json::Value& entry) {
194 if (!entry.isMember(ActivityLog::kKeyType) ||
195 entry[ActivityLog::kKeyType].type() != Json::stringValue) {
196 Err("Can't get entry type.");
197 return false;
198 }
199 string type = entry[ActivityLog::kKeyType].asString();
200 if (type == ActivityLog::kKeyHardwareState)
201 return ParseHardwareState(entry);
202 if (type == ActivityLog::kKeyTimerCallback)
203 return ParseTimerCallback(entry);
204 if (type == ActivityLog::kKeyCallbackRequest)
205 return ParseCallbackRequest(entry);
206 if (type == ActivityLog::kKeyGesture)
207 return ParseGesture(entry);
208 if (type == ActivityLog::kKeyPropChange)
209 return ParsePropChange(entry);
210 Err("Unknown entry type");
211 return false;
212 }
213
ParseHardwareState(const Json::Value & entry)214 bool ActivityReplay::ParseHardwareState(const Json::Value& entry) {
215 HardwareState hs = HardwareState();
216 if (!entry.isMember(ActivityLog::kKeyHardwareStateButtonsDown)) {
217 Err("Unable to parse hardware state buttons down");
218 return false;
219 }
220 hs.buttons_down = entry[ActivityLog::kKeyHardwareStateButtonsDown].asUInt();
221 if (!entry.isMember(ActivityLog::kKeyHardwareStateTouchCnt)) {
222 Err("Unable to parse hardware state touch count");
223 return false;
224 }
225 hs.touch_cnt = entry[ActivityLog::kKeyHardwareStateTouchCnt].asUInt();
226 if (!entry.isMember(ActivityLog::kKeyHardwareStateTimestamp)) {
227 Err("Unable to parse hardware state timestamp");
228 return false;
229 }
230 hs.timestamp = entry[ActivityLog::kKeyHardwareStateTimestamp].asDouble();
231 if (!entry.isMember(ActivityLog::kKeyHardwareStateFingers)) {
232 Err("Unable to parse hardware state fingers");
233 return false;
234 }
235 Json::Value fingers = entry[ActivityLog::kKeyHardwareStateFingers];
236 // Sanity check
237 const size_t kMaxFingers = 30;
238 if (fingers.size() > kMaxFingers) {
239 Err("Too many fingers in hardware state");
240 return false;
241 }
242 FingerState fs[kMaxFingers];
243 for (size_t i = 0; i < fingers.size(); ++i) {
244 if (!fingers.isValidIndex(i)) {
245 Err("Invalid entry at index %zu", i);
246 return false;
247 }
248 const Json::Value& finger_state = fingers[static_cast<int>(i)];
249 if (!ParseFingerState(finger_state, &fs[i]))
250 return false;
251 }
252 hs.fingers = fs;
253 hs.finger_cnt = fingers.size();
254 // There may not have rel_ entries for old logs
255 if (entry.isMember(ActivityLog::kKeyHardwareStateRelX)) {
256 hs.rel_x = entry[ActivityLog::kKeyHardwareStateRelX].asDouble();
257 if (!entry.isMember(ActivityLog::kKeyHardwareStateRelY)) {
258 Err("Unable to parse hardware state rel_y");
259 return false;
260 }
261 hs.rel_x = entry[ActivityLog::kKeyHardwareStateRelY].asDouble();
262 if (!entry.isMember(ActivityLog::kKeyHardwareStateRelWheel)) {
263 Err("Unable to parse hardware state rel_wheel");
264 return false;
265 }
266 hs.rel_wheel = entry[ActivityLog::kKeyHardwareStateRelWheel].asDouble();
267 if (!entry.isMember(ActivityLog::kKeyHardwareStateRelHWheel)) {
268 Err("Unable to parse hardware state rel_hwheel");
269 return false;
270 }
271 hs.rel_hwheel = entry[ActivityLog::kKeyHardwareStateRelHWheel].asDouble();
272 }
273 log_.LogHardwareState(hs);
274 return true;
275 }
276
ParseFingerState(const Json::Value & entry,FingerState * out_fs)277 bool ActivityReplay::ParseFingerState(const Json::Value& entry,
278 FingerState* out_fs) {
279 if (!entry.isMember(ActivityLog::kKeyFingerStateTouchMajor)) {
280 Err("can't parse finger's touch major");
281 return false;
282 }
283 out_fs->touch_major =
284 entry[ActivityLog::kKeyFingerStateTouchMajor].asDouble();
285 if (!entry.isMember(ActivityLog::kKeyFingerStateTouchMinor)) {
286 Err("can't parse finger's touch minor");
287 return false;
288 }
289 out_fs->touch_minor =
290 entry[ActivityLog::kKeyFingerStateTouchMinor].asDouble();
291 if (!entry.isMember(ActivityLog::kKeyFingerStateWidthMajor)) {
292 Err("can't parse finger's width major");
293 return false;
294 }
295 out_fs->width_major =
296 entry[ActivityLog::kKeyFingerStateWidthMajor].asDouble();
297 if (!entry.isMember(ActivityLog::kKeyFingerStateWidthMinor)) {
298 Err("can't parse finger's width minor");
299 return false;
300 }
301 out_fs->width_minor =
302 entry[ActivityLog::kKeyFingerStateWidthMinor].asDouble();
303 if (!entry.isMember(ActivityLog::kKeyFingerStatePressure)) {
304 Err("can't parse finger's pressure");
305 return false;
306 }
307 out_fs->pressure = entry[ActivityLog::kKeyFingerStatePressure].asDouble();
308 if (!entry.isMember(ActivityLog::kKeyFingerStateOrientation)) {
309 Err("can't parse finger's orientation");
310 return false;
311 }
312 out_fs->orientation =
313 entry[ActivityLog::kKeyFingerStateOrientation].asDouble();
314 if (!entry.isMember(ActivityLog::kKeyFingerStatePositionX)) {
315 Err("can't parse finger's position x");
316 return false;
317 }
318 out_fs->position_x = entry[ActivityLog::kKeyFingerStatePositionX].asDouble();
319 if (!entry.isMember(ActivityLog::kKeyFingerStatePositionY)) {
320 Err("can't parse finger's position y");
321 return false;
322 }
323 out_fs->position_y = entry[ActivityLog::kKeyFingerStatePositionY].asDouble();
324 if (!entry.isMember(ActivityLog::kKeyFingerStateTrackingId)) {
325 Err("can't parse finger's tracking id");
326 return false;
327 }
328 out_fs->tracking_id = entry[ActivityLog::kKeyFingerStateTrackingId].asInt();
329 if (!entry.isMember(ActivityLog::kKeyFingerStateFlags))
330 Err("can't parse finger's flags; continuing.");
331 out_fs->flags = entry[ActivityLog::kKeyFingerStateFlags].asUInt();
332 return true;
333 }
334
ParseTimerCallback(const Json::Value & entry)335 bool ActivityReplay::ParseTimerCallback(const Json::Value& entry) {
336 if (!entry.isMember(ActivityLog::kKeyTimerNow)) {
337 Err("can't parse timercallback");
338 return false;
339 }
340 log_.LogTimerCallback(entry[ActivityLog::kKeyTimerNow].asDouble());
341 return true;
342 }
343
ParseCallbackRequest(const Json::Value & entry)344 bool ActivityReplay::ParseCallbackRequest(const Json::Value& entry) {
345 if (!entry.isMember(ActivityLog::kKeyCallbackRequestWhen)) {
346 Err("can't parse callback request");
347 return false;
348 }
349 log_.LogCallbackRequest(
350 entry[ActivityLog::kKeyCallbackRequestWhen].asDouble());
351 return true;
352 }
353
ParseGesture(const Json::Value & entry)354 bool ActivityReplay::ParseGesture(const Json::Value& entry) {
355 if (!entry.isMember(ActivityLog::kKeyGestureType)) {
356 Err("can't parse gesture type");
357 return false;
358 }
359 string gesture_type = entry[ActivityLog::kKeyGestureType].asString();
360 Gesture gs;
361
362 if (!entry.isMember(ActivityLog::kKeyGestureStartTime)) {
363 Err("Failed to parse gesture start time");
364 return false;
365 }
366 gs.start_time = entry[ActivityLog::kKeyGestureStartTime].asDouble();
367 if (!entry.isMember(ActivityLog::kKeyGestureEndTime)) {
368 Err("Failed to parse gesture end time");
369 return false;
370 }
371 gs.end_time = entry[ActivityLog::kKeyGestureEndTime].asDouble();
372
373 if (gesture_type == ActivityLog::kValueGestureTypeContactInitiated) {
374 gs.type = kGestureTypeContactInitiated;
375 } else if (gesture_type == ActivityLog::kValueGestureTypeMove) {
376 if (!ParseGestureMove(entry, &gs))
377 return false;
378 } else if (gesture_type == ActivityLog::kValueGestureTypeScroll) {
379 if (!ParseGestureScroll(entry, &gs))
380 return false;
381 } else if (gesture_type == ActivityLog::kValueGestureTypeSwipe) {
382 if (!ParseGestureSwipe(entry, &gs))
383 return false;
384 } else if (gesture_type == ActivityLog::kValueGestureTypeSwipeLift) {
385 if (!ParseGestureSwipeLift(entry, &gs))
386 return false;
387 } else if (gesture_type == ActivityLog::kValueGestureTypePinch) {
388 if (!ParseGesturePinch(entry, &gs))
389 return false;
390 } else if (gesture_type == ActivityLog::kValueGestureTypeButtonsChange) {
391 if (!ParseGestureButtonsChange(entry, &gs))
392 return false;
393 } else if (gesture_type == ActivityLog::kValueGestureTypeFling) {
394 if (!ParseGestureFling(entry, &gs))
395 return false;
396 } else if (gesture_type == ActivityLog::kValueGestureTypeMetrics) {
397 if (!ParseGestureMetrics(entry, &gs))
398 return false;
399 } else {
400 gs.type = kGestureTypeNull;
401 }
402 log_.LogGesture(gs);
403 return true;
404 }
405
ParseGestureMove(const Json::Value & entry,Gesture * out_gs)406 bool ActivityReplay::ParseGestureMove(const Json::Value& entry,
407 Gesture* out_gs) {
408 out_gs->type = kGestureTypeMove;
409 if (!entry.isMember(ActivityLog::kKeyGestureDX)) {
410 Err("can't parse move dx");
411 return false;
412 }
413 out_gs->details.move.dx = entry[ActivityLog::kKeyGestureDX].asDouble();
414 if (!entry.isMember(ActivityLog::kKeyGestureDY)) {
415 Err("can't parse move dy");
416 return false;
417 }
418 out_gs->details.move.dy = entry[ActivityLog::kKeyGestureDY].asDouble();
419 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) {
420 Err("can't parse move ordinal_dx");
421 return false;
422 }
423 out_gs->details.move.ordinal_dx =
424 entry[ActivityLog::kKeyGestureOrdinalDX].asDouble();
425 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) {
426 Err("can't parse move ordinal_dy");
427 return false;
428 }
429 out_gs->details.move.ordinal_dy =
430 entry[ActivityLog::kKeyGestureOrdinalDY].asDouble();
431 return true;
432 }
433
ParseGestureScroll(const Json::Value & entry,Gesture * out_gs)434 bool ActivityReplay::ParseGestureScroll(const Json::Value& entry,
435 Gesture* out_gs) {
436 out_gs->type = kGestureTypeScroll;
437 if (!entry.isMember(ActivityLog::kKeyGestureDX)) {
438 Err("can't parse scroll dx");
439 return false;
440 }
441 out_gs->details.scroll.dx =
442 entry[ActivityLog::kKeyGestureDX].asDouble();
443 if (!entry.isMember(ActivityLog::kKeyGestureDY)) {
444 Err("can't parse scroll dy");
445 return false;
446 }
447 out_gs->details.scroll.dy =
448 entry[ActivityLog::kKeyGestureDY].asDouble();
449 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) {
450 Err("can't parse scroll ordinal_dx");
451 return false;
452 }
453 out_gs->details.scroll.ordinal_dx =
454 entry[ActivityLog::kKeyGestureOrdinalDX].asDouble();
455 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) {
456 Err("can't parse scroll ordinal_dy");
457 return false;
458 }
459 out_gs->details.scroll.ordinal_dy =
460 entry[ActivityLog::kKeyGestureOrdinalDY].asDouble();
461 return true;
462 }
463
ParseGestureSwipe(const Json::Value & entry,Gesture * out_gs)464 bool ActivityReplay::ParseGestureSwipe(const Json::Value& entry,
465 Gesture* out_gs) {
466 out_gs->type = kGestureTypeSwipe;
467 if (!entry.isMember(ActivityLog::kKeyGestureDX)) {
468 Err("can't parse swipe dx");
469 return false;
470 }
471 out_gs->details.swipe.dx = entry[ActivityLog::kKeyGestureDX].asDouble();
472 if (!entry.isMember(ActivityLog::kKeyGestureDY)) {
473 Err("can't parse swipe dy");
474 return false;
475 }
476 out_gs->details.swipe.dy = entry[ActivityLog::kKeyGestureDY].asDouble();
477 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) {
478 Err("can't parse swipe ordinal_dx");
479 return false;
480 }
481 out_gs->details.swipe.ordinal_dx =
482 entry[ActivityLog::kKeyGestureOrdinalDX].asDouble();
483 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) {
484 Err("can't parse swipe ordinal_dy");
485 return false;
486 }
487 out_gs->details.swipe.ordinal_dy =
488 entry[ActivityLog::kKeyGestureOrdinalDY].asDouble();
489 return true;
490 }
491
ParseGestureSwipeLift(const Json::Value & entry,Gesture * out_gs)492 bool ActivityReplay::ParseGestureSwipeLift(const Json::Value& entry,
493 Gesture* out_gs) {
494 out_gs->type = kGestureTypeSwipeLift;
495 return true;
496 }
497
ParseGesturePinch(const Json::Value & entry,Gesture * out_gs)498 bool ActivityReplay::ParseGesturePinch(const Json::Value& entry,
499 Gesture* out_gs) {
500 out_gs->type = kGestureTypePinch;
501 if (!entry.isMember(ActivityLog::kKeyGesturePinchDZ)) {
502 Err("can't parse pinch dz");
503 return false;
504 }
505 out_gs->details.pinch.dz = entry[ActivityLog::kKeyGesturePinchDZ].asDouble();
506 if (!entry.isMember(ActivityLog::kKeyGesturePinchOrdinalDZ)) {
507 Err("can't parse pinch ordinal_dz");
508 return false;
509 }
510 out_gs->details.pinch.ordinal_dz =
511 entry[ActivityLog::kKeyGesturePinchOrdinalDZ].asDouble();
512 if (!entry.isMember(ActivityLog::kKeyGesturePinchZoomState)) {
513 Err("can't parse pinch zoom_state");
514 return false;
515 }
516 out_gs->details.pinch.zoom_state =
517 entry[ActivityLog::kKeyGesturePinchZoomState].asInt();
518 return true;
519 }
520
ParseGestureButtonsChange(const Json::Value & entry,Gesture * out_gs)521 bool ActivityReplay::ParseGestureButtonsChange(const Json::Value& entry,
522 Gesture* out_gs) {
523 out_gs->type = kGestureTypeButtonsChange;
524 if (!entry.isMember(ActivityLog::kKeyGestureButtonsChangeDown)) {
525 Err("can't parse buttons down");
526 return false;
527 }
528 out_gs->details.buttons.down =
529 entry[ActivityLog::kKeyGestureButtonsChangeDown].asUInt();
530 if (!entry.isMember(ActivityLog::kKeyGestureButtonsChangeUp)) {
531 Err("can't parse buttons up");
532 return false;
533 }
534 out_gs->details.buttons.up =
535 entry[ActivityLog::kKeyGestureButtonsChangeUp].asUInt();
536 return true;
537 }
538
ParseGestureFling(const Json::Value & entry,Gesture * out_gs)539 bool ActivityReplay::ParseGestureFling(const Json::Value& entry,
540 Gesture* out_gs) {
541 out_gs->type = kGestureTypeFling;
542 if (!entry.isMember(ActivityLog::kKeyGestureFlingVX)) {
543 Err("can't parse fling vx");
544 return false;
545 }
546 out_gs->details.fling.vx = entry[ActivityLog::kKeyGestureFlingVX].asDouble();
547 if (!entry.isMember(ActivityLog::kKeyGestureFlingVY)) {
548 Err("can't parse fling vy");
549 return false;
550 }
551 out_gs->details.fling.vy = entry[ActivityLog::kKeyGestureFlingVY].asDouble();
552 if (!entry.isMember(ActivityLog::kKeyGestureFlingOrdinalVX)) {
553 Err("can't parse fling ordinal_vx");
554 return false;
555 }
556 out_gs->details.fling.ordinal_vx =
557 entry[ActivityLog::kKeyGestureFlingOrdinalVX].asDouble();
558 if (!entry.isMember(ActivityLog::kKeyGestureFlingOrdinalVY)) {
559 Err("can't parse fling ordinal_vy");
560 return false;
561 }
562 out_gs->details.fling.ordinal_vy =
563 entry[ActivityLog::kKeyGestureFlingOrdinalVY].asDouble();
564 if (!entry.isMember(ActivityLog::kKeyGestureFlingState)) {
565 Err("can't parse scroll is_scroll_begin");
566 return false;
567 }
568 out_gs->details.fling.fling_state =
569 entry[ActivityLog::kKeyGestureFlingState].asInt();
570 return true;
571 }
572
ParseGestureMetrics(const Json::Value & entry,Gesture * out_gs)573 bool ActivityReplay::ParseGestureMetrics(const Json::Value& entry,
574 Gesture* out_gs) {
575 out_gs->type = kGestureTypeMetrics;
576 if (!entry.isMember(ActivityLog::kKeyGestureMetricsData1)) {
577 Err("can't parse metrics data 1");
578 return false;
579 }
580 out_gs->details.metrics.data[0] =
581 entry[ActivityLog::kKeyGestureMetricsData1].asDouble();
582 if (!entry.isMember(ActivityLog::kKeyGestureMetricsData2)) {
583 Err("can't parse metrics data 2");
584 return false;
585 }
586 out_gs->details.metrics.data[1] =
587 entry[ActivityLog::kKeyGestureMetricsData2].asDouble();
588 if (!entry.isMember(ActivityLog::kKeyGestureMetricsType)) {
589 Err("can't parse metrics type");
590 return false;
591 }
592 int type = entry[ActivityLog::kKeyGestureMetricsType].asInt();
593 if (type == 0) {
594 out_gs->details.metrics.type = kGestureMetricsTypeNoisyGround;
595 return true;
596 }
597 out_gs->details.metrics.type = kGestureMetricsTypeUnknown;
598 return true;
599 }
600
ParsePropChange(const Json::Value & entry)601 bool ActivityReplay::ParsePropChange(const Json::Value& entry) {
602 ActivityLog::PropChangeEntry prop_change;
603 if (!entry.isMember(ActivityLog::kKeyPropChangeType)) {
604 Err("Can't get prop change type");
605 return false;
606 }
607 string type = entry[ActivityLog::kKeyPropChangeType].asString();
608
609 if (type == ActivityLog::kValuePropChangeTypeBool) {
610 if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
611 Err("Can't parse prop change value");
612 return false;
613 }
614 prop_change.value =
615 static_cast<GesturesPropBool>(
616 entry[ActivityLog::kKeyPropChangeValue].asBool());
617 } else if (type == ActivityLog::kValuePropChangeTypeDouble) {
618 if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
619 Err("Can't parse prop change value");
620 return false;
621 }
622 prop_change.value =
623 entry[ActivityLog::kKeyPropChangeValue].asDouble();
624 } else if (type == ActivityLog::kValuePropChangeTypeInt) {
625 if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
626 Err("Can't parse prop change value");
627 return false;
628 }
629 prop_change.value =
630 entry[ActivityLog::kKeyPropChangeValue].asInt();
631 } else if (type == ActivityLog::kValuePropChangeTypeShort) {
632 if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
633 Err("Can't parse prop change value");
634 return false;
635 }
636 prop_change.value =
637 static_cast<short>(
638 entry[ActivityLog::kKeyPropChangeValue].asInt());
639 } else {
640 Err("Unable to parse prop change type %s", type.c_str());
641 return false;
642 }
643 if (!entry.isMember(ActivityLog::kKeyPropChangeName)) {
644 Err("Unable to parse prop change name.");
645 return false;
646 }
647 const string* stored_name =
648 new string(entry[ActivityLog::kKeyPropChangeName].asString()); // alloc
649 // transfer ownership:
650 names_.push_back(std::shared_ptr<const string>(stored_name));
651 prop_change.name = stored_name->c_str();
652 log_.LogPropChange(prop_change);
653 return true;
654 }
655
656 // Replay the log and verify the output in a strict way.
Replay(Interpreter * interpreter,MetricsProperties * mprops)657 void ActivityReplay::Replay(Interpreter* interpreter,
658 MetricsProperties* mprops) {
659 interpreter->Initialize(&hwprops_, nullptr, mprops, this);
660
661 stime_t last_timeout_req = -1.0;
662 // Use last_gs to save a copy of last gesture.
663 Gesture last_gs;
664 for (size_t i = 0; i < log_.size(); ++i) {
665 ActivityLog::Entry* entry = log_.GetEntry(i);
666 std::visit(
667 Visitor {
668 [&interpreter, &last_timeout_req](HardwareState hs) {
669 last_timeout_req = -1.0;
670 for (size_t i = 0; i < hs.finger_cnt; i++)
671 Log("Input Finger ID: %d", hs.fingers[i].tracking_id);
672 interpreter->SyncInterpret(hs, &last_timeout_req);
673 },
674 [&interpreter, &last_timeout_req]
675 (ActivityLog::TimerCallbackEntry now) {
676 last_timeout_req = -1.0;
677 interpreter->HandleTimer(now.timestamp, &last_timeout_req);
678 },
679 [&i, &last_timeout_req](ActivityLog::CallbackRequestEntry when) {
680 if (!DoubleEq(last_timeout_req, when.timestamp)) {
681 Err("Expected timeout request of %f, "
682 "but log has %f (entry idx %zu)",
683 last_timeout_req, when.timestamp, i);
684 }
685 },
686 [this](Gesture gesture) {
687 bool matched = false;
688 while (!consumed_gestures_.empty() && !matched) {
689 if (consumed_gestures_.front() == gesture) {
690 Log("Gesture matched:\n Actual gesture: %s.\n"
691 "Expected gesture: %s",
692 consumed_gestures_.front().String().c_str(),
693 gesture.String().c_str());
694 matched = true;
695 } else {
696 Log("Unmatched actual gesture: %s\n",
697 consumed_gestures_.front().String().c_str());
698 ADD_FAILURE();
699 }
700 consumed_gestures_.pop_front();
701 }
702 if (!matched) {
703 Log("Missing logged gesture: %s", gesture.String().c_str());
704 ADD_FAILURE();
705 }
706 },
707 [this](ActivityLog::PropChangeEntry prop_change) {
708 ReplayPropChange(prop_change);
709 },
710 [](auto arg) {
711 Err("Unknown ActivityLog type");
712 }
713 }, entry->details);
714 }
715 while (!consumed_gestures_.empty()) {
716 Log("Unmatched actual gesture: %s\n",
717 consumed_gestures_.front().String().c_str());
718 ADD_FAILURE();
719 consumed_gestures_.pop_front();
720 }
721 }
722
ConsumeGesture(const Gesture & gesture)723 void ActivityReplay::ConsumeGesture(const Gesture& gesture) {
724 consumed_gestures_.push_back(gesture);
725 }
726
ReplayPropChange(const ActivityLog::PropChangeEntry & entry)727 bool ActivityReplay::ReplayPropChange(
728 const ActivityLog::PropChangeEntry& entry) {
729 if (!prop_reg_) {
730 Err("Missing prop registry.");
731 return false;
732 }
733 ::set<Property*> props = prop_reg_->props();
734 Property* prop = nullptr;
735 for (::set<Property*>::iterator it = props.begin(), e = props.end(); it != e;
736 ++it) {
737 prop = *it;
738 if (strcmp(prop->name(), entry.name.c_str()) == 0)
739 break;
740 prop = nullptr;
741 }
742 if (!prop) {
743 Err("Unable to find prop %s to set.", entry.name.c_str());
744 return false;
745 }
746 bool valid_property = true;
747 Json::Value value;
748 std::visit(
749 Visitor {
750 [&value](GesturesPropBool entry_value) {
751 value = Json::Value(static_cast<bool>(entry_value));
752 },
753 [&value](double entry_value) {
754 value = Json::Value(entry_value);
755 },
756 [&value](int entry_value) {
757 value = Json::Value(entry_value);
758 },
759 [&value](short entry_value) {
760 value = Json::Value(entry_value);
761 },
762 [&valid_property](auto arg) {
763 valid_property = false;
764 Err("Invalid property type");
765 }
766 }, entry.value);
767 if (valid_property) {
768 prop->SetValue(value);
769 prop->HandleGesturesPropWritten();
770 }
771 return valid_property;
772 }
773
774 } // namespace gestures
775