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