blob: 13a7dedb87fbfe23793d1c2b44ec035a1b6c2422 [file]
// Copyright (c) 2012 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_log.h"
#include <errno.h>
#include <fcntl.h>
#include <set>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <base/file_util.h>
#include <base/file_path.h>
#include <base/json/json_writer.h>
#include <base/stringprintf.h>
#include <base/values.h>
#include "gestures/include/logging.h"
#include "gestures/include/prop_registry.h"
// This should be set by build system:
#ifndef VCSID
#define VCSID "Unknown"
#endif // VCSID
using base::FundamentalValue;
using std::set;
using std::string;
namespace gestures {
ActivityLog::ActivityLog(PropRegistry* prop_reg)
: head_idx_(0), size_(0), max_fingers_(0), prop_reg_(prop_reg) {}
void ActivityLog::SetHardwareProperties(const HardwareProperties& hwprops) {
hwprops_ = hwprops;
max_fingers_ = hwprops.max_finger_cnt;
finger_states_.reset(new FingerState[kBufferSize * max_fingers_]);
}
void ActivityLog::LogHardwareState(const HardwareState& hwstate) {
Entry* entry = PushBack();
entry->type = kHardwareState;
entry->details.hwstate = hwstate;
if (hwstate.finger_cnt > max_fingers_) {
Err("Too many fingers! Max is %zu, but I got %d",
max_fingers_, hwstate.finger_cnt);
entry->details.hwstate.fingers = NULL;
return;
}
if (!finger_states_.get())
return;
entry->details.hwstate.fingers = &finger_states_[TailIdx() * max_fingers_];
std::copy(&hwstate.fingers[0], &hwstate.fingers[hwstate.finger_cnt],
entry->details.hwstate.fingers);
}
void ActivityLog::LogTimerCallback(stime_t now) {
Entry* entry = PushBack();
entry->type = kTimerCallback;
entry->details.timestamp = now;
}
void ActivityLog::LogCallbackRequest(stime_t when) {
Entry* entry = PushBack();
entry->type = kCallbackRequest;
entry->details.timestamp = when;
}
void ActivityLog::LogGesture(const Gesture& gesture) {
Entry* entry = PushBack();
entry->type = kGesture;
entry->details.gesture = gesture;
}
void ActivityLog::LogPropChange(const PropChangeEntry& prop_change) {
Entry* entry = PushBack();
entry->type = kPropChange;
entry->details.prop_change = prop_change;
}
void ActivityLog::Dump(const char* filename) {
string data = Encode();
std::string fn(filename);
FilePath fp(fn);
file_util::WriteFile(fp, data.c_str(), data.size());
}
ActivityLog::Entry* ActivityLog::PushBack() {
if (size_ == kBufferSize) {
Entry* ret = &buffer_[head_idx_];
head_idx_ = (head_idx_ + 1) % kBufferSize;
return ret;
}
++size_;
return &buffer_[TailIdx()];
}
namespace {
const char kEntryPadding[] = " ";
const char kSubEntryPadding[] = " ";
const char kSubSubEntryPadding[] = " ";
}
::Value* ActivityLog::EncodeHardwareProperties() const {
DictionaryValue* ret = new DictionaryValue;
ret->Set(kKeyHardwarePropLeft, new FundamentalValue(hwprops_.left));
ret->Set(kKeyHardwarePropTop, new FundamentalValue(hwprops_.top));
ret->Set(kKeyHardwarePropRight, new FundamentalValue(hwprops_.right));
ret->Set(kKeyHardwarePropBottom, new FundamentalValue(hwprops_.bottom));
ret->Set(kKeyHardwarePropXResolution, new FundamentalValue(hwprops_.res_x));
ret->Set(kKeyHardwarePropYResolution, new FundamentalValue(hwprops_.res_y));
ret->Set(kKeyHardwarePropXDpi, new FundamentalValue(hwprops_.screen_x_dpi));
ret->Set(kKeyHardwarePropYDpi, new FundamentalValue(hwprops_.screen_y_dpi));
ret->Set(kKeyHardwarePropMaxFingerCount,
new FundamentalValue(hwprops_.max_finger_cnt));
ret->Set(kKeyHardwarePropMaxTouchCount,
new FundamentalValue(hwprops_.max_touch_cnt));
ret->Set(kKeyHardwarePropSupportsT5R2,
new FundamentalValue(hwprops_.supports_t5r2 != 0));
ret->Set(kKeyHardwarePropSemiMt,
new FundamentalValue(hwprops_.support_semi_mt != 0));
ret->Set(kKeyHardwarePropIsButtonPad,
new FundamentalValue(hwprops_.is_button_pad != 0));
return ret;
}
::Value* ActivityLog::EncodeHardwareState(const HardwareState& hwstate) {
DictionaryValue* ret = new DictionaryValue;
ret->Set(kKeyType, new StringValue(kKeyHardwareState));
ret->Set(kKeyHardwareStateButtonsDown,
new FundamentalValue(hwstate.buttons_down));
ret->Set(kKeyHardwareStateTouchCnt,
new FundamentalValue(hwstate.touch_cnt));
ret->Set(kKeyHardwareStateTimestamp,
new FundamentalValue(hwstate.timestamp));
ListValue* fingers = new ListValue;
for (size_t i = 0; i < hwstate.finger_cnt; ++i) {
const FingerState& fs = hwstate.fingers[i];
DictionaryValue* finger = new DictionaryValue;
finger->Set(kKeyFingerStateTouchMajor,
new FundamentalValue(fs.touch_major));
finger->Set(kKeyFingerStateTouchMinor,
new FundamentalValue(fs.touch_minor));
finger->Set(kKeyFingerStateWidthMajor,
new FundamentalValue(fs.width_major));
finger->Set(kKeyFingerStateWidthMinor,
new FundamentalValue(fs.width_minor));
finger->Set(kKeyFingerStatePressure,
new FundamentalValue(fs.pressure));
finger->Set(kKeyFingerStateOrientation,
new FundamentalValue(fs.orientation));
finger->Set(kKeyFingerStatePositionX,
new FundamentalValue(fs.position_x));
finger->Set(kKeyFingerStatePositionY,
new FundamentalValue(fs.position_y));
finger->Set(kKeyFingerStateTrackingId,
new FundamentalValue(fs.tracking_id));
finger->Set(kKeyFingerStateFlags,
new FundamentalValue(static_cast<int>(fs.flags)));
fingers->Append(finger);
}
ret->Set(kKeyHardwareStateFingers, fingers);
return ret;
}
::Value* ActivityLog::EncodeTimerCallback(stime_t timestamp) {
DictionaryValue* ret = new DictionaryValue;
ret->Set(kKeyType, new StringValue(kKeyTimerCallback));
ret->Set(kKeyTimerCallbackNow, new FundamentalValue(timestamp));
return ret;
}
::Value* ActivityLog::EncodeCallbackRequest(stime_t timestamp) {
DictionaryValue* ret = new DictionaryValue;
ret->Set(kKeyType, new StringValue(kKeyCallbackRequest));
ret->Set(kKeyCallbackRequestWhen, new FundamentalValue(timestamp));
return ret;
}
::Value* ActivityLog::EncodeGesture(const Gesture& gesture) {
DictionaryValue* ret = new DictionaryValue;
ret->Set(kKeyType, new StringValue(kKeyGesture));
ret->Set(kKeyGestureStartTime, new FundamentalValue(gesture.start_time));
ret->Set(kKeyGestureEndTime, new FundamentalValue(gesture.end_time));
bool handled = false;
switch (gesture.type) {
case kGestureTypeNull:
handled = true;
ret->Set(kKeyGestureType, new StringValue("null"));
break;
case kGestureTypeContactInitiated:
handled = true;
ret->Set(kKeyGestureType,
new StringValue(kValueGestureTypeContactInitiated));
break;
case kGestureTypeMove:
handled = true;
ret->Set(kKeyGestureType,
new StringValue(kValueGestureTypeMove));
ret->Set(kKeyGestureMoveDX,
new FundamentalValue(gesture.details.move.dx));
ret->Set(kKeyGestureMoveDY,
new FundamentalValue(gesture.details.move.dy));
break;
case kGestureTypeScroll:
handled = true;
ret->Set(kKeyGestureType,
new StringValue(kValueGestureTypeScroll));
ret->Set(kKeyGestureScrollDX,
new FundamentalValue(gesture.details.scroll.dx));
ret->Set(kKeyGestureScrollDY,
new FundamentalValue(gesture.details.scroll.dy));
break;
case kGestureTypePinch:
handled = true;
ret->Set(kKeyGestureType,
new StringValue(kValueGestureTypePinch));
ret->Set(kKeyGesturePinchDZ,
new FundamentalValue(gesture.details.pinch.dz));
break;
case kGestureTypeButtonsChange:
handled = true;
ret->Set(kKeyGestureType,
new StringValue(kValueGestureTypeButtonsChange));
ret->Set(kKeyGestureButtonsChangeDown,
new FundamentalValue(
static_cast<int>(gesture.details.buttons.down)));
ret->Set(kKeyGestureButtonsChangeUp,
new FundamentalValue(
static_cast<int>(gesture.details.buttons.up)));
break;
case kGestureTypeFling:
handled = true;
ret->Set(kKeyGestureType,
new StringValue(kValueGestureTypeFling));
ret->Set(kKeyGestureFlingVX,
new FundamentalValue(gesture.details.fling.vx));
ret->Set(kKeyGestureFlingVY,
new FundamentalValue(gesture.details.fling.vy));
ret->Set(kKeyGestureFlingState,
new FundamentalValue(
static_cast<int>(gesture.details.fling.fling_state)));
break;
case kGestureTypeSwipe:
handled = true;
ret->Set(kKeyGestureType,
new StringValue(kValueGestureTypeSwipe));
ret->Set(kKeyGestureSwipeDX,
new FundamentalValue(gesture.details.swipe.dx));
break;
}
if (!handled)
ret->Set(kKeyGestureType,
new StringValue(StringPrintf("Unhandled %d", gesture.type)));
return ret;
}
::Value* ActivityLog::EncodePropChange(const PropChangeEntry& prop_change) {
DictionaryValue* ret = new DictionaryValue;
ret->Set(kKeyType, new StringValue(kKeyPropChange));
ret->Set(kKeyPropChangeName, new StringValue(prop_change.name));
FundamentalValue* val = NULL;
StringValue* type = NULL;
switch (prop_change.type) {
case PropChangeEntry::kBoolProp:
val = new FundamentalValue(static_cast<bool>(prop_change.value.bool_val));
type = new StringValue(kValuePropChangeTypeBool);
break;
case PropChangeEntry::kDoubleProp:
val = new FundamentalValue(prop_change.value.double_val);
type = new StringValue(kValuePropChangeTypeDouble);
break;
case PropChangeEntry::kIntProp:
val = new FundamentalValue(prop_change.value.int_val);
type = new StringValue(kValuePropChangeTypeInt);
break;
case PropChangeEntry::kShortProp:
val = new FundamentalValue(prop_change.value.short_val);
type = new StringValue(kValuePropChangeTypeShort);
break;
}
if (val)
ret->Set(kKeyPropChangeValue, val);
if (type)
ret->Set(kKeyPropChangeType, type);
return ret;
}
::Value* ActivityLog::EncodePropRegistry() {
DictionaryValue* ret = new DictionaryValue;
if (!prop_reg_)
return ret;
const set<Property*>& props = prop_reg_->props();
for (set<Property*>::const_iterator it = props.begin(), e = props.end();
it != e; ++it) {
ret->Set((*it)->name(), (*it)->NewValue());
}
return ret;
}
DictionaryValue* ActivityLog::EncodeCommonInfo() {
DictionaryValue* root = new DictionaryValue;
ListValue* entries = new ListValue;
for (size_t i = 0; i < size_; ++i) {
const Entry& entry = buffer_[(i + head_idx_) % kBufferSize];
switch (entry.type) {
case kHardwareState:
entries->Append(EncodeHardwareState(entry.details.hwstate));
continue;
case kTimerCallback:
entries->Append(EncodeTimerCallback(entry.details.timestamp));
continue;
case kCallbackRequest:
entries->Append(EncodeCallbackRequest(entry.details.timestamp));
continue;
case kGesture:
entries->Append(EncodeGesture(entry.details.gesture));
continue;
case kPropChange:
entries->Append(EncodePropChange(entry.details.prop_change));
continue;
}
Err("Unknown entry type %d", entry.type);
}
root->Set(kKeyRoot, entries);
root->Set(kKeyHardwarePropRoot, EncodeHardwareProperties());
return root;
}
DictionaryValue* ActivityLog::AddEncodeInfo(DictionaryValue* root) {
root->Set("version", new FundamentalValue(1));
string gestures_version = VCSID;
// Strip tailing whitespace.
TrimWhitespaceASCII(gestures_version, TRIM_ALL, &gestures_version);
root->Set("gesturesVersion", new StringValue(gestures_version));
root->Set(kKeyProperties, EncodePropRegistry());
return root;
}
string ActivityLog::Encode() {
DictionaryValue *root;
root = EncodeCommonInfo();
root = AddEncodeInfo(root);
string out;
base::JSONWriter::Write(root, true, &out);
return out;
}
const char ActivityLog::kKeyInterpreterName[] = "interpreterName";
const char ActivityLog::kKeyNext[] = "nextLayer";
const char ActivityLog::kKeyRoot[] = "entries";
const char ActivityLog::kKeyType[] = "type";
const char ActivityLog::kKeyHardwareState[] = "hardwareState";
const char ActivityLog::kKeyTimerCallback[] = "timerCallback";
const char ActivityLog::kKeyCallbackRequest[] = "callbackRequest";
const char ActivityLog::kKeyGesture[] = "gesture";
const char ActivityLog::kKeyPropChange[] = "propertyChange";
const char ActivityLog::kKeyHardwareStateTimestamp[] = "timestamp";
const char ActivityLog::kKeyHardwareStateButtonsDown[] = "buttonsDown";
const char ActivityLog::kKeyHardwareStateTouchCnt[] = "touchCount";
const char ActivityLog::kKeyHardwareStateFingers[] = "fingers";
const char ActivityLog::kKeyFingerStateTouchMajor[] = "touchMajor";
const char ActivityLog::kKeyFingerStateTouchMinor[] = "touchMinor";
const char ActivityLog::kKeyFingerStateWidthMajor[] = "widthMajor";
const char ActivityLog::kKeyFingerStateWidthMinor[] = "widthMinor";
const char ActivityLog::kKeyFingerStatePressure[] = "pressure";
const char ActivityLog::kKeyFingerStateOrientation[] = "orientation";
const char ActivityLog::kKeyFingerStatePositionX[] = "positionX";
const char ActivityLog::kKeyFingerStatePositionY[] = "positionY";
const char ActivityLog::kKeyFingerStateTrackingId[] = "trackingId";
const char ActivityLog::kKeyFingerStateFlags[] = "flags";
const char ActivityLog::kKeyTimerCallbackNow[] = "now";
const char ActivityLog::kKeyCallbackRequestWhen[] = "when";
const char ActivityLog::kKeyGestureType[] = "gestureType";
const char ActivityLog::kValueGestureTypeContactInitiated[] =
"contactInitiated";
const char ActivityLog::kValueGestureTypeMove[] = "move";
const char ActivityLog::kValueGestureTypeScroll[] = "scroll";
const char ActivityLog::kValueGestureTypePinch[] = "pinch";
const char ActivityLog::kValueGestureTypeButtonsChange[] = "buttonsChange";
const char ActivityLog::kValueGestureTypeFling[] = "fling";
const char ActivityLog::kValueGestureTypeSwipe[] = "swipe";
const char ActivityLog::kKeyGestureStartTime[] = "startTime";
const char ActivityLog::kKeyGestureEndTime[] = "endTime";
const char ActivityLog::kKeyGestureMoveDX[] = "dx";
const char ActivityLog::kKeyGestureMoveDY[] = "dy";
const char ActivityLog::kKeyGestureScrollDX[] = "dx";
const char ActivityLog::kKeyGestureScrollDY[] = "dy";
const char ActivityLog::kKeyGesturePinchDZ[] = "dz";
const char ActivityLog::kKeyGestureButtonsChangeDown[] = "down";
const char ActivityLog::kKeyGestureButtonsChangeUp[] = "up";
const char ActivityLog::kKeyGestureFlingVX[] = "vx";
const char ActivityLog::kKeyGestureFlingVY[] = "vy";
const char ActivityLog::kKeyGestureFlingState[] = "flingState";
const char ActivityLog::kKeyGestureSwipeDX[] = "dx";
const char ActivityLog::kKeyPropChangeType[] = "propChangeType";
const char ActivityLog::kKeyPropChangeName[] = "name";
const char ActivityLog::kKeyPropChangeValue[] = "value";
const char ActivityLog::kValuePropChangeTypeBool[] = "bool";
const char ActivityLog::kValuePropChangeTypeDouble[] = "double";
const char ActivityLog::kValuePropChangeTypeInt[] = "int";
const char ActivityLog::kValuePropChangeTypeShort[] = "short";
const char ActivityLog::kKeyHardwarePropRoot[] = "hardwareProperties";
const char ActivityLog::kKeyHardwarePropLeft[] = "left";
const char ActivityLog::kKeyHardwarePropTop[] = "top";
const char ActivityLog::kKeyHardwarePropRight[] = "right";
const char ActivityLog::kKeyHardwarePropBottom[] = "bottom";
const char ActivityLog::kKeyHardwarePropXResolution[] = "xResolution";
const char ActivityLog::kKeyHardwarePropYResolution[] = "yResolution";
const char ActivityLog::kKeyHardwarePropXDpi[] = "xDpi";
const char ActivityLog::kKeyHardwarePropYDpi[] = "yDpi";
const char ActivityLog::kKeyHardwarePropMaxFingerCount[] = "maxFingerCount";
const char ActivityLog::kKeyHardwarePropMaxTouchCount[] = "maxTouchCount";
const char ActivityLog::kKeyHardwarePropSupportsT5R2[] = "supportsT5R2";
const char ActivityLog::kKeyHardwarePropSemiMt[] = "semiMt";
const char ActivityLog::kKeyHardwarePropIsButtonPad[] = "isButtonPad";
const char ActivityLog::kKeyProperties[] = "properties";
} // namespace gestures