blob: d258461958e6b37cb9677fdc4cc67f767db479f4 [file] [log] [blame]
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gestures/include/activity_replay.h"
#include <limits.h>
#include <string>
#include <gtest/gtest.h>
#include <json/reader.h>
#include <json/writer.h>
#include "gestures/include/logging.h"
#include "gestures/include/prop_registry.h"
#include "gestures/include/set.h"
#include "gestures/include/unittest_util.h"
#include "gestures/include/util.h"
using std::endl;
using std::set;
using std::string;
namespace gestures {
ActivityReplay::ActivityReplay(PropRegistry* prop_reg)
: log_(NULL), prop_reg_(prop_reg) {}
bool ActivityReplay::Parse(const string& data) {
std::set<string> emptyset;
return Parse(data, emptyset);
}
bool ActivityReplay::Parse(const string& data,
const std::set<string>& honor_props) {
log_.Clear();
names_.clear();
string error_msg;
Json::Value root;
{
Json::Reader reader;
if (!reader.parse(data, root, false)) { // root modified in parse()
Err("Parse failed: %s", error_msg.c_str());
return false;
}
}
if (root.type() != Json::objectValue) {
Err("Root type is %d, but expected %d (dictionary)",
root.type(), Json::objectValue);
return false;
}
// Get and apply user-configurable properties
Json::Value props_dict =
root.get(ActivityLog::kKeyProperties, Json::Value());
if (root.isMember(ActivityLog::kKeyProperties) &&
!ParseProperties(props_dict, honor_props)) {
Err("Unable to parse properties.");
return false;
}
// Get and apply hardware properties
if (!root.isMember(ActivityLog::kKeyHardwarePropRoot)) {
Err("Unable to get hwprops dict.");
return false;
}
Json::Value hwprops_dict =
root.get(ActivityLog::kKeyHardwarePropRoot, Json::Value());
if (!ParseHardwareProperties(hwprops_dict, &hwprops_))
return false;
log_.SetHardwareProperties(hwprops_);
Json::Value entries = root.get(ActivityLog::kKeyRoot, Json::Value());
char next_layer_path[PATH_MAX];
snprintf(next_layer_path, sizeof(next_layer_path), "%s.%s",
ActivityLog::kKeyNext, ActivityLog::kKeyRoot);
if (!root.isMember(ActivityLog::kKeyRoot)) {
Err("Unable to get list of entries from root.");
return false;
}
if (root.isMember(next_layer_path)) {
Json::Value next_layer_entries = root[next_layer_path];
if (entries.size() < next_layer_entries.size())
entries = next_layer_entries;
}
for (size_t i = 0; i < entries.size(); ++i) {
Json::Value entry = entries.get(i, Json::Value());
if (!entries.isValidIndex(i)) {
Err("Invalid entry at index %zu", i);
return false;
}
if (!ParseEntry(entry))
return false;
}
return true;
}
bool ActivityReplay::ParseProperties(const Json::Value& dict,
const std::set<string>& honor_props) {
if (!prop_reg_)
return true;
::set<Property*> props = prop_reg_->props();
for (::set<Property*>::const_iterator it = props.begin(), e = props.end();
it != e; ++it) {
const char* key = (*it)->name();
// TODO(clchiou): This is just a emporary workaround for property changes.
// I will work out a solution for this kind of changes.
if (!strcmp(key, "Compute Surface Area from Pressure") ||
!strcmp(key, "Touchpad Device Output Bias on X-Axis") ||
!strcmp(key, "Touchpad Device Output Bias on Y-Axis")) {
continue;
}
if (!honor_props.empty() && !SetContainsValue(honor_props, string(key)))
continue;
if (!dict.isMember(key)) {
Err("Log doesn't have value for property %s", key);
continue;
}
const Json::Value& value = dict[key];
if (!(*it)->SetValue(value)) {
Err("Unable to restore value for property %s", key);
return false;
}
}
return true;
}
#define PARSE_HP(obj, key, IsTypeFn, KeyFn, var, VarType, required) \
do { \
if (!obj.isMember(key) || !obj[key].IsTypeFn()) { \
Err("Parse failed for key %s", key); \
if (required) \
return false; \
} \
var = obj[key].KeyFn(); \
} while (0)
bool ActivityReplay::ParseHardwareProperties(const Json::Value& obj,
HardwareProperties* out_props) {
HardwareProperties props;
PARSE_HP(obj, ActivityLog::kKeyHardwarePropLeft, isDouble, asDouble,
props.left, float, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropTop, isDouble, asDouble,
props.top, float, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropRight, isDouble, asDouble,
props.right, float, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropBottom, isDouble, asDouble,
props.bottom, float, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropXResolution, isDouble, asDouble,
props.res_x, float, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropYResolution, isDouble, asDouble,
props.res_y, float, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropXDpi, isDouble, asDouble,
props.screen_x_dpi, float, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropYDpi, isDouble, asDouble,
props.screen_y_dpi, float, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropOrientationMinimum,
isDouble, asDouble, props.orientation_minimum, float, false);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropOrientationMaximum,
isDouble, asDouble, props.orientation_maximum, float, false);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropMaxFingerCount, isInt, asUInt,
props.max_finger_cnt, unsigned short, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropMaxTouchCount, isInt, asUInt,
props.max_touch_cnt, unsigned short, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropSupportsT5R2, isBool, asBool,
props.supports_t5r2, bool, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropSemiMt,isBool, asBool,
props.support_semi_mt, bool, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropIsButtonPad,isBool, asBool,
props.is_button_pad, bool, true);
PARSE_HP(obj, ActivityLog::kKeyHardwarePropHasWheel,isBool, asBool,
props.has_wheel, bool, true);
*out_props = props;
return true;
}
#undef PARSE_HP
bool ActivityReplay::ParseEntry(const Json::Value& entry) {
if (!entry.isMember(ActivityLog::kKeyType) ||
entry[ActivityLog::kKeyType].type() != Json::stringValue) {
Err("Can't get entry type.");
return false;
}
string type = entry[ActivityLog::kKeyType].asString();
if (type == ActivityLog::kKeyHardwareState)
return ParseHardwareState(entry);
if (type == ActivityLog::kKeyTimerCallback)
return ParseTimerCallback(entry);
if (type == ActivityLog::kKeyCallbackRequest)
return ParseCallbackRequest(entry);
if (type == ActivityLog::kKeyGesture)
return ParseGesture(entry);
if (type == ActivityLog::kKeyPropChange)
return ParsePropChange(entry);
Err("Unknown entry type");
return false;
}
bool ActivityReplay::ParseHardwareState(const Json::Value& entry) {
HardwareState hs = HardwareState();
if (!entry.isMember(ActivityLog::kKeyHardwareStateButtonsDown)) {
Err("Unable to parse hardware state buttons down");
return false;
}
hs.buttons_down = entry[ActivityLog::kKeyHardwareStateButtonsDown].asUInt();
if (!entry.isMember(ActivityLog::kKeyHardwareStateTouchCnt)) {
Err("Unable to parse hardware state touch count");
return false;
}
hs.touch_cnt = entry[ActivityLog::kKeyHardwareStateTouchCnt].asUInt();
if (!entry.isMember(ActivityLog::kKeyHardwareStateTimestamp)) {
Err("Unable to parse hardware state timestamp");
return false;
}
hs.timestamp = entry[ActivityLog::kKeyHardwareStateTimestamp].asDouble();
if (!entry.isMember(ActivityLog::kKeyHardwareStateFingers)) {
Err("Unable to parse hardware state fingers");
return false;
}
Json::Value fingers = entry[ActivityLog::kKeyHardwareStateFingers];
// Sanity check
if (fingers.size() > 30) {
Err("Too many fingers in hardware state");
return false;
}
FingerState fs[fingers.size()];
for (size_t i = 0; i < fingers.size(); ++i) {
if (!fingers.isValidIndex(i)) {
Err("Invalid entry at index %zu", i);
return false;
}
const Json::Value& finger_state = fingers[static_cast<int>(i)];
if (!ParseFingerState(finger_state, &fs[i]))
return false;
}
hs.fingers = fs;
hs.finger_cnt = fingers.size();
// There may not have rel_ entries for old logs
if (entry.isMember(ActivityLog::kKeyHardwareStateRelX)) {
hs.rel_x = entry[ActivityLog::kKeyHardwareStateRelX].asDouble();
if (!entry.isMember(ActivityLog::kKeyHardwareStateRelY)) {
Err("Unable to parse hardware state rel_y");
return false;
}
hs.rel_x = entry[ActivityLog::kKeyHardwareStateRelY].asDouble();
if (!entry.isMember(ActivityLog::kKeyHardwareStateRelWheel)) {
Err("Unable to parse hardware state rel_wheel");
return false;
}
hs.rel_wheel = entry[ActivityLog::kKeyHardwareStateRelWheel].asDouble();
if (!entry.isMember(ActivityLog::kKeyHardwareStateRelHWheel)) {
Err("Unable to parse hardware state rel_hwheel");
return false;
}
hs.rel_hwheel = entry[ActivityLog::kKeyHardwareStateRelHWheel].asDouble();
}
log_.LogHardwareState(hs);
return true;
}
bool ActivityReplay::ParseFingerState(const Json::Value& entry,
FingerState* out_fs) {
if (!entry.isMember(ActivityLog::kKeyFingerStateTouchMajor)) {
Err("can't parse finger's touch major");
return false;
}
out_fs->touch_major =
entry[ActivityLog::kKeyFingerStateTouchMajor].asDouble();
if (!entry.isMember(ActivityLog::kKeyFingerStateTouchMinor)) {
Err("can't parse finger's touch minor");
return false;
}
out_fs->touch_minor =
entry[ActivityLog::kKeyFingerStateTouchMinor].asDouble();
if (!entry.isMember(ActivityLog::kKeyFingerStateWidthMajor)) {
Err("can't parse finger's width major");
return false;
}
out_fs->width_major =
entry[ActivityLog::kKeyFingerStateWidthMajor].asDouble();
if (!entry.isMember(ActivityLog::kKeyFingerStateWidthMinor)) {
Err("can't parse finger's width minor");
return false;
}
out_fs->width_minor =
entry[ActivityLog::kKeyFingerStateWidthMinor].asDouble();
if (!entry.isMember(ActivityLog::kKeyFingerStatePressure)) {
Err("can't parse finger's pressure");
return false;
}
out_fs->pressure = entry[ActivityLog::kKeyFingerStatePressure].asDouble();
if (!entry.isMember(ActivityLog::kKeyFingerStateOrientation)) {
Err("can't parse finger's orientation");
return false;
}
out_fs->orientation =
entry[ActivityLog::kKeyFingerStateOrientation].asDouble();
if (!entry.isMember(ActivityLog::kKeyFingerStatePositionX)) {
Err("can't parse finger's position x");
return false;
}
out_fs->position_x = entry[ActivityLog::kKeyFingerStatePositionX].asDouble();
if (!entry.isMember(ActivityLog::kKeyFingerStatePositionY)) {
Err("can't parse finger's position y");
return false;
}
out_fs->position_y = entry[ActivityLog::kKeyFingerStatePositionY].asDouble();
if (!entry.isMember(ActivityLog::kKeyFingerStateTrackingId)) {
Err("can't parse finger's tracking id");
return false;
}
out_fs->tracking_id = entry[ActivityLog::kKeyFingerStateTrackingId].asInt();
if (!entry.isMember(ActivityLog::kKeyFingerStateFlags))
Err("can't parse finger's flags; continuing.");
out_fs->flags = entry[ActivityLog::kKeyFingerStateFlags].asUInt();
return true;
}
bool ActivityReplay::ParseTimerCallback(const Json::Value& entry) {
if (!entry.isMember(ActivityLog::kKeyTimerCallbackNow)) {
Err("can't parse timercallback");
return false;
}
log_.LogTimerCallback(entry[ActivityLog::kKeyTimerCallbackNow].asDouble());
return true;
}
bool ActivityReplay::ParseCallbackRequest(const Json::Value& entry) {
if (!entry.isMember(ActivityLog::kKeyCallbackRequestWhen)) {
Err("can't parse callback request");
return false;
}
log_.LogCallbackRequest(
entry[ActivityLog::kKeyCallbackRequestWhen].asDouble());
return true;
}
bool ActivityReplay::ParseGesture(const Json::Value& entry) {
if (!entry.isMember(ActivityLog::kKeyGestureType)) {
Err("can't parse gesture type");
return false;
}
string gesture_type = entry[ActivityLog::kKeyGestureType].asString();
Gesture gs;
if (!entry.isMember(ActivityLog::kKeyGestureStartTime)) {
Err("Failed to parse gesture start time");
return false;
}
gs.start_time = entry[ActivityLog::kKeyGestureStartTime].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureEndTime)) {
Err("Failed to parse gesture end time");
return false;
}
gs.end_time = entry[ActivityLog::kKeyGestureEndTime].asDouble();
if (gesture_type == ActivityLog::kValueGestureTypeContactInitiated) {
gs.type = kGestureTypeContactInitiated;
} else if (gesture_type == ActivityLog::kValueGestureTypeMove) {
if (!ParseGestureMove(entry, &gs))
return false;
} else if (gesture_type == ActivityLog::kValueGestureTypeScroll) {
if (!ParseGestureScroll(entry, &gs))
return false;
} else if (gesture_type == ActivityLog::kValueGestureTypeSwipe) {
if (!ParseGestureSwipe(entry, &gs))
return false;
} else if (gesture_type == ActivityLog::kValueGestureTypeSwipeLift) {
if (!ParseGestureSwipeLift(entry, &gs))
return false;
} else if (gesture_type == ActivityLog::kValueGestureTypePinch) {
if (!ParseGesturePinch(entry, &gs))
return false;
} else if (gesture_type == ActivityLog::kValueGestureTypeButtonsChange) {
if (!ParseGestureButtonsChange(entry, &gs))
return false;
} else if (gesture_type == ActivityLog::kValueGestureTypeFling) {
if (!ParseGestureFling(entry, &gs))
return false;
} else if (gesture_type == ActivityLog::kValueGestureTypeMetrics) {
if (!ParseGestureMetrics(entry, &gs))
return false;
} else {
gs.type = kGestureTypeNull;
}
log_.LogGesture(gs);
return true;
}
bool ActivityReplay::ParseGestureMove(const Json::Value& entry,
Gesture* out_gs) {
out_gs->type = kGestureTypeMove;
if (!entry.isMember(ActivityLog::kKeyGestureMoveDX)) {
Err("can't parse move dx");
return false;
}
out_gs->details.move.dx = entry[ActivityLog::kKeyGestureMoveDX].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureMoveDY)) {
Err("can't parse move dy");
return false;
}
out_gs->details.move.dy = entry[ActivityLog::kKeyGestureMoveDY].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureMoveOrdinalDX)) {
Err("can't parse move ordinal_dx");
return false;
}
out_gs->details.move.ordinal_dx =
entry[ActivityLog::kKeyGestureMoveOrdinalDX].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureMoveOrdinalDY)) {
Err("can't parse move ordinal_dy");
return false;
}
out_gs->details.move.ordinal_dy =
entry[ActivityLog::kKeyGestureMoveOrdinalDY].asDouble();
return true;
}
bool ActivityReplay::ParseGestureScroll(const Json::Value& entry,
Gesture* out_gs) {
out_gs->type = kGestureTypeScroll;
if (!entry.isMember(ActivityLog::kKeyGestureScrollDX)) {
Err("can't parse scroll dx");
return false;
}
out_gs->details.scroll.dx =
entry[ActivityLog::kKeyGestureScrollDX].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureScrollDY)) {
Err("can't parse scroll dy");
return false;
}
out_gs->details.scroll.dy =
entry[ActivityLog::kKeyGestureScrollDY].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureScrollOrdinalDX)) {
Err("can't parse scroll ordinal_dx");
return false;
}
out_gs->details.scroll.ordinal_dx =
entry[ActivityLog::kKeyGestureScrollOrdinalDX].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureScrollOrdinalDY)) {
Err("can't parse scroll ordinal_dy");
return false;
}
out_gs->details.scroll.ordinal_dy =
entry[ActivityLog::kKeyGestureScrollOrdinalDY].asDouble();
return true;
}
bool ActivityReplay::ParseGestureSwipe(const Json::Value& entry,
Gesture* out_gs) {
out_gs->type = kGestureTypeSwipe;
if (!entry.isMember(ActivityLog::kKeyGestureSwipeDX)) {
Err("can't parse swipe dx");
return false;
}
out_gs->details.swipe.dx = entry[ActivityLog::kKeyGestureSwipeDX].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureSwipeDY)) {
Err("can't parse swipe dy");
return false;
}
out_gs->details.swipe.dy = entry[ActivityLog::kKeyGestureSwipeDY].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureSwipeOrdinalDX)) {
Err("can't parse swipe ordinal_dx");
return false;
}
out_gs->details.swipe.ordinal_dx =
entry[ActivityLog::kKeyGestureSwipeOrdinalDX].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureSwipeOrdinalDY)) {
Err("can't parse swipe ordinal_dy");
return false;
}
out_gs->details.swipe.ordinal_dy =
entry[ActivityLog::kKeyGestureSwipeOrdinalDY].asDouble();
return true;
}
bool ActivityReplay::ParseGestureSwipeLift(const Json::Value& entry,
Gesture* out_gs) {
out_gs->type = kGestureTypeSwipeLift;
return true;
}
bool ActivityReplay::ParseGesturePinch(const Json::Value& entry,
Gesture* out_gs) {
out_gs->type = kGestureTypePinch;
if (!entry.isMember(ActivityLog::kKeyGesturePinchDZ)) {
Err("can't parse pinch dz");
return false;
}
out_gs->details.pinch.dz = entry[ActivityLog::kKeyGesturePinchDZ].asDouble();
if (!entry.isMember(ActivityLog::kKeyGesturePinchOrdinalDZ)) {
Err("can't parse pinch ordinal_dz");
return false;
}
out_gs->details.pinch.ordinal_dz =
entry[ActivityLog::kKeyGesturePinchOrdinalDZ].asDouble();
if (!entry.isMember(ActivityLog::kKeyGesturePinchZoomState)) {
Err("can't parse pinch zoom_state");
return false;
}
out_gs->details.pinch.zoom_state =
entry[ActivityLog::kKeyGesturePinchZoomState].asInt();
return true;
}
bool ActivityReplay::ParseGestureButtonsChange(const Json::Value& entry,
Gesture* out_gs) {
out_gs->type = kGestureTypeButtonsChange;
if (!entry.isMember(ActivityLog::kKeyGestureButtonsChangeDown)) {
Err("can't parse buttons down");
return false;
}
out_gs->details.buttons.down =
entry[ActivityLog::kKeyGestureButtonsChangeDown].asUInt();
if (!entry.isMember(ActivityLog::kKeyGestureButtonsChangeUp)) {
Err("can't parse buttons up");
return false;
}
out_gs->details.buttons.up =
entry[ActivityLog::kKeyGestureButtonsChangeUp].asUInt();
return true;
}
bool ActivityReplay::ParseGestureFling(const Json::Value& entry,
Gesture* out_gs) {
out_gs->type = kGestureTypeFling;
if (!entry.isMember(ActivityLog::kKeyGestureFlingVX)) {
Err("can't parse fling vx");
return false;
}
out_gs->details.fling.vx = entry[ActivityLog::kKeyGestureFlingVX].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureFlingVY)) {
Err("can't parse fling vy");
return false;
}
out_gs->details.fling.vy = entry[ActivityLog::kKeyGestureFlingVY].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureFlingOrdinalVX)) {
Err("can't parse fling ordinal_vx");
return false;
}
out_gs->details.fling.ordinal_vx =
entry[ActivityLog::kKeyGestureFlingOrdinalVX].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureFlingOrdinalVY)) {
Err("can't parse fling ordinal_vy");
return false;
}
out_gs->details.fling.ordinal_vy =
entry[ActivityLog::kKeyGestureFlingOrdinalVY].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureFlingState)) {
Err("can't parse scroll is_scroll_begin");
return false;
}
out_gs->details.fling.fling_state =
entry[ActivityLog::kKeyGestureFlingState].asInt();
return true;
}
bool ActivityReplay::ParseGestureMetrics(const Json::Value& entry,
Gesture* out_gs) {
out_gs->type = kGestureTypeMetrics;
if (!entry.isMember(ActivityLog::kKeyGestureMetricsData1)) {
Err("can't parse metrics data 1");
return false;
}
out_gs->details.metrics.data[0] =
entry[ActivityLog::kKeyGestureMetricsData1].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureMetricsData2)) {
Err("can't parse metrics data 2");
return false;
}
out_gs->details.metrics.data[1] =
entry[ActivityLog::kKeyGestureMetricsData2].asDouble();
if (!entry.isMember(ActivityLog::kKeyGestureMetricsType)) {
Err("can't parse metrics type");
return false;
}
int type = entry[ActivityLog::kKeyGestureMetricsType].asInt();
if (type == 0) {
out_gs->details.metrics.type = kGestureMetricsTypeNoisyGround;
return true;
}
out_gs->details.metrics.type = kGestureMetricsTypeUnknown;
return true;
}
bool ActivityReplay::ParsePropChange(const Json::Value& entry) {
ActivityLog::PropChangeEntry prop_change;
if (!entry.isMember(ActivityLog::kKeyPropChangeType)) {
Err("Can't get prop change type");
return false;
}
string type = entry[ActivityLog::kKeyPropChangeType].asString();
if (type == ActivityLog::kValuePropChangeTypeBool) {
prop_change.type = ActivityLog::PropChangeEntry::kBoolProp;
if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
Err("Can't parse prop change value");
return false;
}
prop_change.value.bool_val =
entry[ActivityLog::kKeyPropChangeValue].asBool();
} else if (type == ActivityLog::kValuePropChangeTypeDouble) {
prop_change.type = ActivityLog::PropChangeEntry::kDoubleProp;
if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
Err("Can't parse prop change value");
return false;
}
prop_change.value.double_val =
entry[ActivityLog::kKeyPropChangeValue].asDouble();
} else if (type == ActivityLog::kValuePropChangeTypeInt) {
prop_change.type = ActivityLog::PropChangeEntry::kIntProp;
if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
Err("Can't parse prop change value");
return false;
}
prop_change.value.int_val =
entry[ActivityLog::kKeyPropChangeValue].asInt();
} else if (type == ActivityLog::kValuePropChangeTypeShort) {
prop_change.type = ActivityLog::PropChangeEntry::kIntProp;
if (!entry.isMember(ActivityLog::kKeyPropChangeValue)) {
Err("Can't parse prop change value");
return false;
}
prop_change.value.short_val =
entry[ActivityLog::kKeyPropChangeValue].asInt();
} else {
Err("Unable to parse prop change type %s", type.c_str());
return false;
}
if (!entry.isMember(ActivityLog::kKeyPropChangeName)) {
Err("Unable to parse prop change name.");
return false;
}
const string* stored_name =
new string(entry[ActivityLog::kKeyPropChangeName].asString()); // alloc
// transfer ownership:
names_.push_back(std::tr1::shared_ptr<const string>(stored_name));
prop_change.name = stored_name->c_str();
log_.LogPropChange(prop_change);
return true;
}
// Replay the log and verify the output in a strict way.
void ActivityReplay::Replay(Interpreter* interpreter,
MetricsProperties* mprops) {
interpreter->Initialize(&hwprops_, NULL, mprops, this);
stime_t last_timeout_req = -1.0;
// Use last_gs to save a copy of last gesture.
Gesture last_gs;
for (size_t i = 0; i < log_.size(); ++i) {
ActivityLog::Entry* entry = log_.GetEntry(i);
switch (entry->type) {
case ActivityLog::kHardwareState: {
last_timeout_req = -1.0;
HardwareState hs = entry->details.hwstate;
for (size_t i = 0; i < hs.finger_cnt; i++)
Log("Input Finger ID: %d", hs.fingers[i].tracking_id);
interpreter->SyncInterpret(&hs, &last_timeout_req);
break;
}
case ActivityLog::kTimerCallback: {
last_timeout_req = -1.0;
interpreter->HandleTimer(entry->details.timestamp, &last_timeout_req);
break;
}
case ActivityLog::kCallbackRequest:
if (!DoubleEq(last_timeout_req, entry->details.timestamp)) {
Err("Expected timeout request of %f, but log has %f (entry idx %zu)",
last_timeout_req, entry->details.timestamp, i);
}
break;
case ActivityLog::kGesture: {
bool matched = false;
while (!consumed_gestures_.empty() && !matched) {
if (consumed_gestures_.front() == entry->details.gesture) {
Log("Gesture matched:\n Actual gesture: %s.\n"
"Expected gesture: %s",
consumed_gestures_.front().String().c_str(),
entry->details.gesture.String().c_str());
matched = true;
} else {
Log("Unmatched actual gesture: %s\n",
consumed_gestures_.front().String().c_str());
ADD_FAILURE();
}
consumed_gestures_.pop_front();
}
if (!matched) {
Log("Missing logged gesture: %s",
entry->details.gesture.String().c_str());
ADD_FAILURE();
}
break;
}
case ActivityLog::kPropChange:
ReplayPropChange(entry->details.prop_change);
break;
}
}
while (!consumed_gestures_.empty()) {
Log("Unmatched actual gesture: %s\n",
consumed_gestures_.front().String().c_str());
ADD_FAILURE();
consumed_gestures_.pop_front();
}
}
void ActivityReplay::ConsumeGesture(const Gesture& gesture) {
consumed_gestures_.push_back(gesture);
}
bool ActivityReplay::ReplayPropChange(
const ActivityLog::PropChangeEntry& entry) {
if (!prop_reg_) {
Err("Missing prop registry.");
return false;
}
::set<Property*> props = prop_reg_->props();
Property* prop = NULL;
for (::set<Property*>::iterator it = props.begin(), e = props.end(); it != e;
++it) {
prop = *it;
if (strcmp(prop->name(), entry.name) == 0)
break;
prop = NULL;
}
if (!prop) {
Err("Unable to find prop %s to set.", entry.name);
return false;
}
Json::Value value;
switch (entry.type) {
case ActivityLog::PropChangeEntry::kBoolProp:
value = Json::Value(entry.value.bool_val);
break;
case ActivityLog::PropChangeEntry::kDoubleProp:
value = Json::Value(entry.value.double_val);
break;
case ActivityLog::PropChangeEntry::kIntProp:
value = Json::Value(entry.value.int_val);
break;
case ActivityLog::PropChangeEntry::kShortProp:
value = Json::Value(entry.value.short_val);
break;
}
prop->SetValue(value);
prop->HandleGesturesPropWritten();
return true;
}
} // namespace gestures