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::kKeyHardwarePropXDpi, isDouble, asDouble,
172 props.screen_x_dpi, float, true);
173 PARSE_HP(obj, ActivityLog::kKeyHardwarePropYDpi, isDouble, asDouble,
174 props.screen_y_dpi, float, true);
175 PARSE_HP(obj, ActivityLog::kKeyHardwarePropOrientationMinimum,
176 isDouble, asDouble, props.orientation_minimum, float, false);
177 PARSE_HP(obj, ActivityLog::kKeyHardwarePropOrientationMaximum,
178 isDouble, asDouble, props.orientation_maximum, float, false);
179 PARSE_HP(obj, ActivityLog::kKeyHardwarePropMaxFingerCount, isInt, asUInt,
180 props.max_finger_cnt, unsigned short, true);
181 PARSE_HP(obj, ActivityLog::kKeyHardwarePropMaxTouchCount, isInt, asUInt,
182 props.max_touch_cnt, unsigned short, true);
183 PARSE_HP(obj, ActivityLog::kKeyHardwarePropSupportsT5R2, isBool, asBool,
184 props.supports_t5r2, bool, true);
185 PARSE_HP(obj, ActivityLog::kKeyHardwarePropSemiMt,isBool, asBool,
186 props.support_semi_mt, bool, true);
187 PARSE_HP(obj, ActivityLog::kKeyHardwarePropIsButtonPad,isBool, asBool,
188 props.is_button_pad, bool, true);
189 PARSE_HP(obj, ActivityLog::kKeyHardwarePropHasWheel,isBool, asBool,
190 props.has_wheel, bool, true);
191 *out_props = props;
192 return true;
193 }
194
195 #undef PARSE_HP
196
ParseEntry(const Json::Value & entry)197 bool ActivityReplay::ParseEntry(const Json::Value& entry) {
198 if (!entry.isMember(ActivityLog::kKeyType) ||
199 entry[ActivityLog::kKeyType].type() != Json::stringValue) {
200 Err("Can't get entry type.");
201 return false;
202 }
203 string type = entry[ActivityLog::kKeyType].asString();
204 if (type == ActivityLog::kKeyHardwareState)
205 return ParseHardwareState(entry);
206 if (type == ActivityLog::kKeyTimerCallback)
207 return ParseTimerCallback(entry);
208 if (type == ActivityLog::kKeyCallbackRequest)
209 return ParseCallbackRequest(entry);
210 if (type == ActivityLog::kKeyGesture)
211 return ParseGesture(entry);
212 if (type == ActivityLog::kKeyPropChange)
213 return ParsePropChange(entry);
214 Err("Unknown entry type");
215 return false;
216 }
217
ParseHardwareState(const Json::Value & entry)218 bool ActivityReplay::ParseHardwareState(const Json::Value& entry) {
219 HardwareState hs = HardwareState();
220 if (!entry.isMember(ActivityLog::kKeyHardwareStateButtonsDown)) {
221 Err("Unable to parse hardware state buttons down");
222 return false;
223 }
224 hs.buttons_down = entry[ActivityLog::kKeyHardwareStateButtonsDown].asUInt();
225 if (!entry.isMember(ActivityLog::kKeyHardwareStateTouchCnt)) {
226 Err("Unable to parse hardware state touch count");
227 return false;
228 }
229 hs.touch_cnt = entry[ActivityLog::kKeyHardwareStateTouchCnt].asUInt();
230 if (!entry.isMember(ActivityLog::kKeyHardwareStateTimestamp)) {
231 Err("Unable to parse hardware state timestamp");
232 return false;
233 }
234 hs.timestamp = entry[ActivityLog::kKeyHardwareStateTimestamp].asDouble();
235 if (!entry.isMember(ActivityLog::kKeyHardwareStateFingers)) {
236 Err("Unable to parse hardware state fingers");
237 return false;
238 }
239 Json::Value fingers = entry[ActivityLog::kKeyHardwareStateFingers];
240 // Sanity check
241 if (fingers.size() > 30) {
242 Err("Too many fingers in hardware state");
243 return false;
244 }
245 FingerState fs[fingers.size()];
246 for (size_t i = 0; i < fingers.size(); ++i) {
247 if (!fingers.isValidIndex(i)) {
248 Err("Invalid entry at index %zu", i);
249 return false;
250 }
251 const Json::Value& finger_state = fingers[static_cast<int>(i)];
252 if (!ParseFingerState(finger_state, &fs[i]))
253 return false;
254 }
255 hs.fingers = fs;
256 hs.finger_cnt = fingers.size();
257 // There may not have rel_ entries for old logs
258 if (entry.isMember(ActivityLog::kKeyHardwareStateRelX)) {
259 hs.rel_x = entry[ActivityLog::kKeyHardwareStateRelX].asDouble();
260 if (!entry.isMember(ActivityLog::kKeyHardwareStateRelY)) {
261 Err("Unable to parse hardware state rel_y");
262 return false;
263 }
264 hs.rel_x = entry[ActivityLog::kKeyHardwareStateRelY].asDouble();
265 if (!entry.isMember(ActivityLog::kKeyHardwareStateRelWheel)) {
266 Err("Unable to parse hardware state rel_wheel");
267 return false;
268 }
269 hs.rel_wheel = entry[ActivityLog::kKeyHardwareStateRelWheel].asDouble();
270 if (!entry.isMember(ActivityLog::kKeyHardwareStateRelHWheel)) {
271 Err("Unable to parse hardware state rel_hwheel");
272 return false;
273 }
274 hs.rel_hwheel = entry[ActivityLog::kKeyHardwareStateRelHWheel].asDouble();
275 }
276 log_.LogHardwareState(hs);
277 return true;
278 }
279
ParseFingerState(const Json::Value & entry,FingerState * out_fs)280 bool ActivityReplay::ParseFingerState(const Json::Value& entry,
281 FingerState* out_fs) {
282 if (!entry.isMember(ActivityLog::kKeyFingerStateTouchMajor)) {
283 Err("can't parse finger's touch major");
284 return false;
285 }
286 out_fs->touch_major =
287 entry[ActivityLog::kKeyFingerStateTouchMajor].asDouble();
288 if (!entry.isMember(ActivityLog::kKeyFingerStateTouchMinor)) {
289 Err("can't parse finger's touch minor");
290 return false;
291 }
292 out_fs->touch_minor =
293 entry[ActivityLog::kKeyFingerStateTouchMinor].asDouble();
294 if (!entry.isMember(ActivityLog::kKeyFingerStateWidthMajor)) {
295 Err("can't parse finger's width major");
296 return false;
297 }
298 out_fs->width_major =
299 entry[ActivityLog::kKeyFingerStateWidthMajor].asDouble();
300 if (!entry.isMember(ActivityLog::kKeyFingerStateWidthMinor)) {
301 Err("can't parse finger's width minor");
302 return false;
303 }
304 out_fs->width_minor =
305 entry[ActivityLog::kKeyFingerStateWidthMinor].asDouble();
306 if (!entry.isMember(ActivityLog::kKeyFingerStatePressure)) {
307 Err("can't parse finger's pressure");
308 return false;
309 }
310 out_fs->pressure = entry[ActivityLog::kKeyFingerStatePressure].asDouble();
311 if (!entry.isMember(ActivityLog::kKeyFingerStateOrientation)) {
312 Err("can't parse finger's orientation");
313 return false;
314 }
315 out_fs->orientation =
316 entry[ActivityLog::kKeyFingerStateOrientation].asDouble();
317 if (!entry.isMember(ActivityLog::kKeyFingerStatePositionX)) {
318 Err("can't parse finger's position x");
319 return false;
320 }
321 out_fs->position_x = entry[ActivityLog::kKeyFingerStatePositionX].asDouble();
322 if (!entry.isMember(ActivityLog::kKeyFingerStatePositionY)) {
323 Err("can't parse finger's position y");
324 return false;
325 }
326 out_fs->position_y = entry[ActivityLog::kKeyFingerStatePositionY].asDouble();
327 if (!entry.isMember(ActivityLog::kKeyFingerStateTrackingId)) {
328 Err("can't parse finger's tracking id");
329 return false;
330 }
331 out_fs->tracking_id = entry[ActivityLog::kKeyFingerStateTrackingId].asInt();
332 if (!entry.isMember(ActivityLog::kKeyFingerStateFlags))
333 Err("can't parse finger's flags; continuing.");
334 out_fs->flags = entry[ActivityLog::kKeyFingerStateFlags].asUInt();
335 return true;
336 }
337
ParseTimerCallback(const Json::Value & entry)338 bool ActivityReplay::ParseTimerCallback(const Json::Value& entry) {
339 if (!entry.isMember(ActivityLog::kKeyTimerNow)) {
340 Err("can't parse timercallback");
341 return false;
342 }
343 log_.LogTimerCallback(entry[ActivityLog::kKeyTimerNow].asDouble());
344 return true;
345 }
346
ParseCallbackRequest(const Json::Value & entry)347 bool ActivityReplay::ParseCallbackRequest(const Json::Value& entry) {
348 if (!entry.isMember(ActivityLog::kKeyCallbackRequestWhen)) {
349 Err("can't parse callback request");
350 return false;
351 }
352 log_.LogCallbackRequest(
353 entry[ActivityLog::kKeyCallbackRequestWhen].asDouble());
354 return true;
355 }
356
ParseGesture(const Json::Value & entry)357 bool ActivityReplay::ParseGesture(const Json::Value& entry) {
358 if (!entry.isMember(ActivityLog::kKeyGestureType)) {
359 Err("can't parse gesture type");
360 return false;
361 }
362 string gesture_type = entry[ActivityLog::kKeyGestureType].asString();
363 Gesture gs;
364
365 if (!entry.isMember(ActivityLog::kKeyGestureStartTime)) {
366 Err("Failed to parse gesture start time");
367 return false;
368 }
369 gs.start_time = entry[ActivityLog::kKeyGestureStartTime].asDouble();
370 if (!entry.isMember(ActivityLog::kKeyGestureEndTime)) {
371 Err("Failed to parse gesture end time");
372 return false;
373 }
374 gs.end_time = entry[ActivityLog::kKeyGestureEndTime].asDouble();
375
376 if (gesture_type == ActivityLog::kValueGestureTypeContactInitiated) {
377 gs.type = kGestureTypeContactInitiated;
378 } else if (gesture_type == ActivityLog::kValueGestureTypeMove) {
379 if (!ParseGestureMove(entry, &gs))
380 return false;
381 } else if (gesture_type == ActivityLog::kValueGestureTypeScroll) {
382 if (!ParseGestureScroll(entry, &gs))
383 return false;
384 } else if (gesture_type == ActivityLog::kValueGestureTypeSwipe) {
385 if (!ParseGestureSwipe(entry, &gs))
386 return false;
387 } else if (gesture_type == ActivityLog::kValueGestureTypeSwipeLift) {
388 if (!ParseGestureSwipeLift(entry, &gs))
389 return false;
390 } else if (gesture_type == ActivityLog::kValueGestureTypePinch) {
391 if (!ParseGesturePinch(entry, &gs))
392 return false;
393 } else if (gesture_type == ActivityLog::kValueGestureTypeButtonsChange) {
394 if (!ParseGestureButtonsChange(entry, &gs))
395 return false;
396 } else if (gesture_type == ActivityLog::kValueGestureTypeFling) {
397 if (!ParseGestureFling(entry, &gs))
398 return false;
399 } else if (gesture_type == ActivityLog::kValueGestureTypeMetrics) {
400 if (!ParseGestureMetrics(entry, &gs))
401 return false;
402 } else {
403 gs.type = kGestureTypeNull;
404 }
405 log_.LogGesture(gs);
406 return true;
407 }
408
ParseGestureMove(const Json::Value & entry,Gesture * out_gs)409 bool ActivityReplay::ParseGestureMove(const Json::Value& entry,
410 Gesture* out_gs) {
411 out_gs->type = kGestureTypeMove;
412 if (!entry.isMember(ActivityLog::kKeyGestureDX)) {
413 Err("can't parse move dx");
414 return false;
415 }
416 out_gs->details.move.dx = entry[ActivityLog::kKeyGestureDX].asDouble();
417 if (!entry.isMember(ActivityLog::kKeyGestureDY)) {
418 Err("can't parse move dy");
419 return false;
420 }
421 out_gs->details.move.dy = entry[ActivityLog::kKeyGestureDY].asDouble();
422 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) {
423 Err("can't parse move ordinal_dx");
424 return false;
425 }
426 out_gs->details.move.ordinal_dx =
427 entry[ActivityLog::kKeyGestureOrdinalDX].asDouble();
428 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) {
429 Err("can't parse move ordinal_dy");
430 return false;
431 }
432 out_gs->details.move.ordinal_dy =
433 entry[ActivityLog::kKeyGestureOrdinalDY].asDouble();
434 return true;
435 }
436
ParseGestureScroll(const Json::Value & entry,Gesture * out_gs)437 bool ActivityReplay::ParseGestureScroll(const Json::Value& entry,
438 Gesture* out_gs) {
439 out_gs->type = kGestureTypeScroll;
440 if (!entry.isMember(ActivityLog::kKeyGestureDX)) {
441 Err("can't parse scroll dx");
442 return false;
443 }
444 out_gs->details.scroll.dx =
445 entry[ActivityLog::kKeyGestureDX].asDouble();
446 if (!entry.isMember(ActivityLog::kKeyGestureDY)) {
447 Err("can't parse scroll dy");
448 return false;
449 }
450 out_gs->details.scroll.dy =
451 entry[ActivityLog::kKeyGestureDY].asDouble();
452 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) {
453 Err("can't parse scroll ordinal_dx");
454 return false;
455 }
456 out_gs->details.scroll.ordinal_dx =
457 entry[ActivityLog::kKeyGestureOrdinalDX].asDouble();
458 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) {
459 Err("can't parse scroll ordinal_dy");
460 return false;
461 }
462 out_gs->details.scroll.ordinal_dy =
463 entry[ActivityLog::kKeyGestureOrdinalDY].asDouble();
464 return true;
465 }
466
ParseGestureSwipe(const Json::Value & entry,Gesture * out_gs)467 bool ActivityReplay::ParseGestureSwipe(const Json::Value& entry,
468 Gesture* out_gs) {
469 out_gs->type = kGestureTypeSwipe;
470 if (!entry.isMember(ActivityLog::kKeyGestureDX)) {
471 Err("can't parse swipe dx");
472 return false;
473 }
474 out_gs->details.swipe.dx = entry[ActivityLog::kKeyGestureDX].asDouble();
475 if (!entry.isMember(ActivityLog::kKeyGestureDY)) {
476 Err("can't parse swipe dy");
477 return false;
478 }
479 out_gs->details.swipe.dy = entry[ActivityLog::kKeyGestureDY].asDouble();
480 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) {
481 Err("can't parse swipe ordinal_dx");
482 return false;
483 }
484 out_gs->details.swipe.ordinal_dx =
485 entry[ActivityLog::kKeyGestureOrdinalDX].asDouble();
486 if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) {
487 Err("can't parse swipe ordinal_dy");
488 return false;
489 }
490 out_gs->details.swipe.ordinal_dy =
491 entry[ActivityLog::kKeyGestureOrdinalDY].asDouble();
492 return true;
493 }
494
ParseGestureSwipeLift(const Json::Value & entry,Gesture * out_gs)495 bool ActivityReplay::ParseGestureSwipeLift(const Json::Value& entry,
496 Gesture* out_gs) {
497 out_gs->type = kGestureTypeSwipeLift;
498 return true;
499 }
500
ParseGesturePinch(const Json::Value & entry,Gesture * out_gs)501 bool ActivityReplay::ParseGesturePinch(const Json::Value& entry,
502 Gesture* out_gs) {
503 out_gs->type = kGestureTypePinch;
504 if (!entry.isMember(ActivityLog::kKeyGesturePinchDZ)) {
505 Err("can't parse pinch dz");
506 return false;
507 }
508 out_gs->details.pinch.dz = entry[ActivityLog::kKeyGesturePinchDZ].asDouble();
509 if (!entry.isMember(ActivityLog::kKeyGesturePinchOrdinalDZ)) {
510 Err("can't parse pinch ordinal_dz");
511 return false;
512 }
513 out_gs->details.pinch.ordinal_dz =
514 entry[ActivityLog::kKeyGesturePinchOrdinalDZ].asDouble();
515 if (!entry.isMember(ActivityLog::kKeyGesturePinchZoomState)) {
516 Err("can't parse pinch zoom_state");
517 return false;
518 }
519 out_gs->details.pinch.zoom_state =
520 entry[ActivityLog::kKeyGesturePinchZoomState].asInt();
521 return true;
522 }
523
ParseGestureButtonsChange(const Json::Value & entry,Gesture * out_gs)524 bool ActivityReplay::ParseGestureButtonsChange(const Json::Value& entry,
525 Gesture* out_gs) {
526 out_gs->type = kGestureTypeButtonsChange;
527 if (!entry.isMember(ActivityLog::kKeyGestureButtonsChangeDown)) {
528 Err("can't parse buttons down");
529 return false;
530 }
531 out_gs->details.buttons.down =
532 entry[ActivityLog::kKeyGestureButtonsChangeDown].asUInt();
533 if (!entry.isMember(ActivityLog::kKeyGestureButtonsChangeUp)) {
534 Err("can't parse buttons up");
535 return false;
536 }
537 out_gs->details.buttons.up =
538 entry[ActivityLog::kKeyGestureButtonsChangeUp].asUInt();
539 return true;
540 }
541
ParseGestureFling(const Json::Value & entry,Gesture * out_gs)542 bool ActivityReplay::ParseGestureFling(const Json::Value& entry,
543 Gesture* out_gs) {
544 out_gs->type = kGestureTypeFling;
545 if (!entry.isMember(ActivityLog::kKeyGestureFlingVX)) {
546 Err("can't parse fling vx");
547 return false;
548 }
549 out_gs->details.fling.vx = entry[ActivityLog::kKeyGestureFlingVX].asDouble();
550 if (!entry.isMember(ActivityLog::kKeyGestureFlingVY)) {
551 Err("can't parse fling vy");
552 return false;
553 }
554 out_gs->details.fling.vy = entry[ActivityLog::kKeyGestureFlingVY].asDouble();
555 if (!entry.isMember(ActivityLog::kKeyGestureFlingOrdinalVX)) {
556 Err("can't parse fling ordinal_vx");
557 return false;
558 }
559 out_gs->details.fling.ordinal_vx =
560 entry[ActivityLog::kKeyGestureFlingOrdinalVX].asDouble();
561 if (!entry.isMember(ActivityLog::kKeyGestureFlingOrdinalVY)) {
562 Err("can't parse fling ordinal_vy");
563 return false;
564 }
565 out_gs->details.fling.ordinal_vy =
566 entry[ActivityLog::kKeyGestureFlingOrdinalVY].asDouble();
567 if (!entry.isMember(ActivityLog::kKeyGestureFlingState)) {
568 Err("can't parse scroll is_scroll_begin");
569 return false;
570 }
571 out_gs->details.fling.fling_state =
572 entry[ActivityLog::kKeyGestureFlingState].asInt();
573 return true;
574 }
575
ParseGestureMetrics(const Json::Value & entry,Gesture * out_gs)576 bool ActivityReplay::ParseGestureMetrics(const Json::Value& entry,
577 Gesture* out_gs) {
578 out_gs->type = kGestureTypeMetrics;
579 if (!entry.isMember(ActivityLog::kKeyGestureMetricsData1)) {
580 Err("can't parse metrics data 1");
581 return false;
582 }
583 out_gs->details.metrics.data[0] =
584 entry[ActivityLog::kKeyGestureMetricsData1].asDouble();
585 if (!entry.isMember(ActivityLog::kKeyGestureMetricsData2)) {
586 Err("can't parse metrics data 2");
587 return false;
588 }
589 out_gs->details.metrics.data[1] =
590 entry[ActivityLog::kKeyGestureMetricsData2].asDouble();
591 if (!entry.isMember(ActivityLog::kKeyGestureMetricsType)) {
592 Err("can't parse metrics type");
593 return false;
594 }
595 int type = entry[ActivityLog::kKeyGestureMetricsType].asInt();
596 if (type == 0) {
597 out_gs->details.metrics.type = kGestureMetricsTypeNoisyGround;
598 return true;
599 }
600 out_gs->details.metrics.type = kGestureMetricsTypeUnknown;
601 return true;
602 }
603
ParsePropChange(const Json::Value & entry)604 bool ActivityReplay::ParsePropChange(const Json::Value& entry) {
605 ActivityLog::PropChangeEntry prop_change;
606 if (!entry.isMember(ActivityLog::kKeyPropChangeType)) {
607 Err("Can't get prop change type");
608 return false;
609 }
610 string type = entry[ActivityLog::kKeyPropChangeType].asString();
611
612 if (type == ActivityLog::kValuePropChangeTypeBool) {
613 if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
614 Err("Can't parse prop change value");
615 return false;
616 }
617 prop_change.value =
618 static_cast<GesturesPropBool>(
619 entry[ActivityLog::kKeyPropChangeValue].asBool());
620 } else if (type == ActivityLog::kValuePropChangeTypeDouble) {
621 if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
622 Err("Can't parse prop change value");
623 return false;
624 }
625 prop_change.value =
626 entry[ActivityLog::kKeyPropChangeValue].asDouble();
627 } else if (type == ActivityLog::kValuePropChangeTypeInt) {
628 if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
629 Err("Can't parse prop change value");
630 return false;
631 }
632 prop_change.value =
633 entry[ActivityLog::kKeyPropChangeValue].asInt();
634 } else if (type == ActivityLog::kValuePropChangeTypeShort) {
635 if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
636 Err("Can't parse prop change value");
637 return false;
638 }
639 prop_change.value =
640 static_cast<short>(
641 entry[ActivityLog::kKeyPropChangeValue].asInt());
642 } else {
643 Err("Unable to parse prop change type %s", type.c_str());
644 return false;
645 }
646 if (!entry.isMember(ActivityLog::kKeyPropChangeName)) {
647 Err("Unable to parse prop change name.");
648 return false;
649 }
650 const string* stored_name =
651 new string(entry[ActivityLog::kKeyPropChangeName].asString()); // alloc
652 // transfer ownership:
653 names_.push_back(std::shared_ptr<const string>(stored_name));
654 prop_change.name = stored_name->c_str();
655 log_.LogPropChange(prop_change);
656 return true;
657 }
658
659 // Replay the log and verify the output in a strict way.
Replay(Interpreter * interpreter,MetricsProperties * mprops)660 void ActivityReplay::Replay(Interpreter* interpreter,
661 MetricsProperties* mprops) {
662 interpreter->Initialize(&hwprops_, nullptr, mprops, this);
663
664 stime_t last_timeout_req = -1.0;
665 // Use last_gs to save a copy of last gesture.
666 Gesture last_gs;
667 for (size_t i = 0; i < log_.size(); ++i) {
668 ActivityLog::Entry* entry = log_.GetEntry(i);
669 std::visit(
670 Visitor {
671 [&interpreter, &last_timeout_req](HardwareState hs) {
672 last_timeout_req = -1.0;
673 for (size_t i = 0; i < hs.finger_cnt; i++)
674 Log("Input Finger ID: %d", hs.fingers[i].tracking_id);
675 interpreter->SyncInterpret(hs, &last_timeout_req);
676 },
677 [&interpreter, &last_timeout_req]
678 (ActivityLog::TimerCallbackEntry now) {
679 last_timeout_req = -1.0;
680 interpreter->HandleTimer(now.timestamp, &last_timeout_req);
681 },
682 [&i, &last_timeout_req](ActivityLog::CallbackRequestEntry when) {
683 if (!DoubleEq(last_timeout_req, when.timestamp)) {
684 Err("Expected timeout request of %f, "
685 "but log has %f (entry idx %zu)",
686 last_timeout_req, when.timestamp, i);
687 }
688 },
689 [this](Gesture gesture) {
690 bool matched = false;
691 while (!consumed_gestures_.empty() && !matched) {
692 if (consumed_gestures_.front() == gesture) {
693 Log("Gesture matched:\n Actual gesture: %s.\n"
694 "Expected gesture: %s",
695 consumed_gestures_.front().String().c_str(),
696 gesture.String().c_str());
697 matched = true;
698 } else {
699 Log("Unmatched actual gesture: %s\n",
700 consumed_gestures_.front().String().c_str());
701 ADD_FAILURE();
702 }
703 consumed_gestures_.pop_front();
704 }
705 if (!matched) {
706 Log("Missing logged gesture: %s", gesture.String().c_str());
707 ADD_FAILURE();
708 }
709 },
710 [this](ActivityLog::PropChangeEntry prop_change) {
711 ReplayPropChange(prop_change);
712 },
713 [](auto arg) {
714 Err("Unknown ActivityLog type");
715 }
716 }, entry->details);
717 }
718 while (!consumed_gestures_.empty()) {
719 Log("Unmatched actual gesture: %s\n",
720 consumed_gestures_.front().String().c_str());
721 ADD_FAILURE();
722 consumed_gestures_.pop_front();
723 }
724 }
725
ConsumeGesture(const Gesture & gesture)726 void ActivityReplay::ConsumeGesture(const Gesture& gesture) {
727 consumed_gestures_.push_back(gesture);
728 }
729
ReplayPropChange(const ActivityLog::PropChangeEntry & entry)730 bool ActivityReplay::ReplayPropChange(
731 const ActivityLog::PropChangeEntry& entry) {
732 if (!prop_reg_) {
733 Err("Missing prop registry.");
734 return false;
735 }
736 ::set<Property*> props = prop_reg_->props();
737 Property* prop = nullptr;
738 for (::set<Property*>::iterator it = props.begin(), e = props.end(); it != e;
739 ++it) {
740 prop = *it;
741 if (strcmp(prop->name(), entry.name.c_str()) == 0)
742 break;
743 prop = nullptr;
744 }
745 if (!prop) {
746 Err("Unable to find prop %s to set.", entry.name.c_str());
747 return false;
748 }
749 bool valid_property = true;
750 Json::Value value;
751 std::visit(
752 Visitor {
753 [&value](GesturesPropBool entry_value) {
754 value = Json::Value(static_cast<bool>(entry_value));
755 },
756 [&value](double entry_value) {
757 value = Json::Value(entry_value);
758 },
759 [&value](int entry_value) {
760 value = Json::Value(entry_value);
761 },
762 [&value](short entry_value) {
763 value = Json::Value(entry_value);
764 },
765 [&valid_property](auto arg) {
766 valid_property = false;
767 Err("Invalid property type");
768 }
769 }, entry.value);
770 if (valid_property) {
771 prop->SetValue(value);
772 prop->HandleGesturesPropWritten();
773 }
774 return valid_property;
775 }
776
777 } // namespace gestures
778