This commit is contained in:
Stephen Birarda 2014-07-02 09:42:32 -07:00
commit 55d8b763c5
16 changed files with 585 additions and 14 deletions

View file

@ -60,6 +60,7 @@
#include <ParticlesScriptingInterface.h>
#include <PerfStat.h>
#include <ResourceCache.h>
#include <UserActivityLogger.h>
#include <UUID.h>
#include <OctreeSceneStats.h>
#include <LocalVoxelsList.h>
@ -269,6 +270,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// set the account manager's root URL and trigger a login request if we don't have the access token
accountManager.setAuthURL(DEFAULT_NODE_AUTH_URL);
UserActivityLogger::getInstance().launch(applicationVersion());
// once the event loop has started, check and signal for an access token
QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
@ -401,7 +403,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
}
Application::~Application() {
int DELAY_TIME = 1000;
UserActivityLogger::getInstance().close(DELAY_TIME);
qInstallMessageHandler(NULL);
// make sure we don't call the idle timer any more
@ -3582,6 +3586,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript
_scriptEnginesHash.insertMulti(scriptURLString, scriptEngine);
_runningScriptsWidget->setRunningScripts(getRunningScripts());
UserActivityLogger::getInstance().loadedScript(scriptURLString);
}
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so

View file

@ -17,6 +17,7 @@
#include <QOpenGLFramebufferObject>
#include <glm/glm.hpp>
#include <UserActivityLogger.h>
#include "Application.h"
@ -61,6 +62,9 @@ void OculusManager::connect() {
_ovrHmd = ovrHmd_Create(0);
if (_ovrHmd) {
if (!_isConnected) {
UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
}
_isConnected = true;
ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc);

View file

@ -13,6 +13,7 @@
#include "Application.h"
#include "SixenseManager.h"
#include "UserActivityLogger.h"
#ifdef HAVE_SIXENSE
const int CALIBRATION_STATE_IDLE = 0;
@ -39,6 +40,7 @@ SixenseManager::SixenseManager() {
sixenseInit();
#endif
_hydrasConnected = false;
_triggerPressed[0] = false;
_bumperPressed[0] = false;
_oldX[0] = -1;
@ -70,7 +72,11 @@ void SixenseManager::setFilter(bool filter) {
void SixenseManager::update(float deltaTime) {
#ifdef HAVE_SIXENSE
if (sixenseGetNumActiveControllers() == 0) {
_hydrasConnected = false;
return;
} else if (!_hydrasConnected) {
_hydrasConnected = true;
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
}
MyAvatar* avatar = Application::getInstance()->getAvatar();
Hand* hand = avatar->getHand();

View file

@ -71,6 +71,7 @@ private:
float _lastDistance;
#endif
bool _hydrasConnected;
quint64 _lastMovement;
glm::vec3 _amountMoved;

View file

@ -135,7 +135,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
args->_elementsTouched++;
// actually render it here...
// we need to iterate the actual modelItems of the element
ModelTreeElement* modelTreeElement = (ModelTreeElement*)element;
ModelTreeElement* modelTreeElement = static_cast<ModelTreeElement*>(element);
QList<ModelItem>& modelItems = modelTreeElement->getModels();

View file

@ -12,8 +12,9 @@
#include "Application.h"
#include "Menu.h"
#include "PreferencesDialog.h"
#include "ModelsBrowser.h"
#include "PreferencesDialog.h"
#include "UserActivityLogger.h"
const int SCROLL_PANEL_BOTTOM_MARGIN = 30;
const int OK_BUTTON_RIGHT_MARGIN = 30;
@ -176,6 +177,7 @@ void PreferencesDialog::savePreferences() {
QString displayNameStr(ui.displayNameEdit->text());
if (displayNameStr != _displayNameString) {
myAvatar->setDisplayName(displayNameStr);
UserActivityLogger::getInstance().changedDisplayName(displayNameStr);
shouldDispatchIdentityPacket = true;
}
@ -183,6 +185,7 @@ void PreferencesDialog::savePreferences() {
if (faceModelURL.toString() != _faceURLString) {
// change the faceModelURL in the profile, it will also update this user's BlendFace
myAvatar->setFaceModelURL(faceModelURL);
UserActivityLogger::getInstance().changedModel("head", faceModelURL.toString());
shouldDispatchIdentityPacket = true;
}
@ -190,6 +193,7 @@ void PreferencesDialog::savePreferences() {
if (skeletonModelURL.toString() != _skeletonURLString) {
// change the skeletonModelURL in the profile, it will also update this user's Body
myAvatar->setSkeletonModelURL(skeletonModelURL);
UserActivityLogger::getInstance().changedModel("skeleton", skeletonModelURL.toString());
shouldDispatchIdentityPacket = true;
}

View file

@ -0,0 +1,136 @@
//
// BillboardOverlay.cpp
//
//
// Created by Clement on 7/1/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "../../Application.h"
#include "BillboardOverlay.h"
BillboardOverlay::BillboardOverlay()
: _manager(NULL),
_scale(1.0f),
_isFacingAvatar(true) {
}
void BillboardOverlay::render() {
if (_billboard.isEmpty()) {
return;
}
if (!_billboardTexture) {
QImage image = QImage::fromData(_billboard);
if (image.format() != QImage::Format_ARGB32) {
image = image.convertToFormat(QImage::Format_ARGB32);
}
_size = image.size();
_billboardTexture.reset(new Texture());
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _size.width(), _size.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
}
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5f);
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glPushMatrix(); {
glTranslatef(_position.x, _position.y, _position.z);
if (_isFacingAvatar) {
// rotate about vertical to face the camera
glm::quat rotation = Application::getInstance()->getCamera()->getRotation();
rotation *= glm::angleAxis(glm::pi<float>(), glm::vec3(0.0f, 1.0f, 0.0f));
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
} else {
glm::vec3 axis = glm::axis(_rotation);
glRotatef(glm::degrees(glm::angle(_rotation)), axis.x, axis.y, axis.z);
}
glScalef(_scale, _scale, _scale);
float maxSize = glm::max(_size.width(), _size.height());
float x = _size.width() / (2.0f * maxSize);
float y = -_size.height() / (2.0f * maxSize);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS); {
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-x, -y);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(x, -y);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(x, y);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-x, y);
} glEnd();
} glPopMatrix();
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
glBindTexture(GL_TEXTURE_2D, 0);
}
void BillboardOverlay::setProperties(const QScriptValue &properties) {
Base3DOverlay::setProperties(properties);
QScriptValue urlValue = properties.property("url");
if (urlValue.isValid()) {
_url = urlValue.toVariant().toString();
setBillboardURL(_url);
}
QScriptValue scaleValue = properties.property("scale");
if (scaleValue.isValid()) {
_scale = scaleValue.toVariant().toFloat();
}
QScriptValue rotationValue = properties.property("rotation");
if (rotationValue.isValid()) {
QScriptValue x = rotationValue.property("x");
QScriptValue y = rotationValue.property("y");
QScriptValue z = rotationValue.property("z");
QScriptValue w = rotationValue.property("w");
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
_rotation.x = x.toVariant().toFloat();
_rotation.y = y.toVariant().toFloat();
_rotation.z = z.toVariant().toFloat();
_rotation.w = w.toVariant().toFloat();
}
}
QScriptValue isFacingAvatarValue = properties.property("isFacingAvatar");
if (isFacingAvatarValue.isValid()) {
_isFacingAvatar = isFacingAvatarValue.toVariant().toBool();
}
}
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
void BillboardOverlay::setBillboardURL(const QUrl url) {
// TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made?
_manager->deleteLater();
_manager = new QNetworkAccessManager();
connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
_manager->get(QNetworkRequest(url));
}
void BillboardOverlay::replyFinished(QNetworkReply* reply) {
// replace our byte array with the downloaded data
_billboard = reply->readAll();
_manager->deleteLater();
_manager = NULL;
}

View file

@ -0,0 +1,46 @@
//
// BillboardOverlay.h
//
//
// Created by Clement on 7/1/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_BillboardOverlay_h
#define hifi_BillboardOverlay_h
#include <QScopedPointer>
#include <QUrl>
#include "Base3DOverlay.h"
#include "../../renderer/TextureCache.h"
class BillboardOverlay : public Base3DOverlay {
Q_OBJECT
public:
BillboardOverlay();
virtual void render();
virtual void setProperties(const QScriptValue& properties);
private slots:
void replyFinished(QNetworkReply* reply);
private:
void setBillboardURL(const QUrl url);
QNetworkAccessManager* _manager;
QUrl _url;
QByteArray _billboard;
QSize _size;
QScopedPointer<Texture> _billboardTexture;
glm::quat _rotation;
float _scale;
bool _isFacingAvatar;
};
#endif // hifi_BillboardOverlay_h

View file

@ -19,7 +19,7 @@
#include "ImageOverlay.h"
ImageOverlay::ImageOverlay() :
_manager(0),
_manager(NULL),
_textureID(0),
_renderImage(false),
_textureBound(false),
@ -37,6 +37,7 @@ ImageOverlay::~ImageOverlay() {
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
void ImageOverlay::setImageURL(const QUrl& url) {
// TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made?
_manager->deleteLater();
_manager = new QNetworkAccessManager();
connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
_manager->get(QNetworkRequest(url));
@ -49,6 +50,7 @@ void ImageOverlay::replyFinished(QNetworkReply* reply) {
_textureImage.loadFromData(rawData);
_renderImage = true;
_manager->deleteLater();
_manager = NULL;
}
void ImageOverlay::render() {

View file

@ -0,0 +1,115 @@
//
// ModelOverlay.cpp
//
//
// Created by Clement on 6/30/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "../../Menu.h"
#include "ModelOverlay.h"
ModelOverlay::ModelOverlay()
: _model(),
_scale(1.0f),
_updateModel(false) {
_model.init();
}
void ModelOverlay::update(float deltatime) {
if (_updateModel) {
_updateModel = false;
_model.setScaleToFit(true, _scale);
_model.setSnapModelToCenter(true);
_model.setRotation(_rotation);
_model.setTranslation(_position);
_model.setURL(_url);
_model.simulate(deltatime, true);
} else {
_model.simulate(deltatime);
}
}
void ModelOverlay::render() {
if (_model.isActive()) {
if (_model.isRenderable()) {
_model.render(_alpha);
}
bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds);
if (displayModelBounds) {
glm::vec3 unRotatedMinimum = _model.getUnscaledMeshExtents().minimum;
glm::vec3 unRotatedMaximum = _model.getUnscaledMeshExtents().maximum;
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
float width = unRotatedExtents.x;
float height = unRotatedExtents.y;
float depth = unRotatedExtents.z;
Extents rotatedExtents = _model.getUnscaledMeshExtents();
calculateRotatedExtents(rotatedExtents, _rotation);
glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum;
const glm::vec3& modelScale = _model.getScale();
glPushMatrix(); {
glTranslatef(_position.x, _position.y, _position.z);
// draw the rotated bounding cube
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glPushMatrix(); {
glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z);
glutWireCube(1.0);
} glPopMatrix();
// draw the model relative bounding box
glm::vec3 axis = glm::axis(_rotation);
glRotatef(glm::degrees(glm::angle(_rotation)), axis.x, axis.y, axis.z);
glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z);
glColor3f(0.0f, 1.0f, 0.0f);
glutWireCube(1.0);
} glPopMatrix();
}
}
}
void ModelOverlay::setProperties(const QScriptValue &properties) {
Base3DOverlay::setProperties(properties);
QScriptValue urlValue = properties.property("url");
if (urlValue.isValid()) {
_url = urlValue.toVariant().toString();
_updateModel = true;
}
QScriptValue scaleValue = properties.property("scale");
if (scaleValue.isValid()) {
_scale = scaleValue.toVariant().toFloat();
_updateModel = true;
}
QScriptValue rotationValue = properties.property("rotation");
if (rotationValue.isValid()) {
QScriptValue x = rotationValue.property("x");
QScriptValue y = rotationValue.property("y");
QScriptValue z = rotationValue.property("z");
QScriptValue w = rotationValue.property("w");
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
_rotation.x = x.toVariant().toFloat();
_rotation.y = y.toVariant().toFloat();
_rotation.z = z.toVariant().toFloat();
_rotation.w = w.toVariant().toFloat();
}
_updateModel = true;
}
if (properties.property("position").isValid()) {
_updateModel = true;
}
}

View file

@ -0,0 +1,38 @@
//
// ModelOverlay.h
//
//
// Created by Clement on 6/30/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ModelOverlay_h
#define hifi_ModelOverlay_h
#include "Base3DOverlay.h"
#include "../../renderer/Model.h"
class ModelOverlay : public Base3DOverlay {
Q_OBJECT
public:
ModelOverlay();
virtual void update(float deltatime);
virtual void render();
virtual void setProperties(const QScriptValue& properties);
private:
Model _model;
QUrl _url;
glm::quat _rotation;
float _scale;
bool _updateModel;
};
#endif // hifi_ModelOverlay_h

View file

@ -10,13 +10,15 @@
#include <Application.h>
#include "BillboardOverlay.h"
#include "Cube3DOverlay.h"
#include "ImageOverlay.h"
#include "Line3DOverlay.h"
#include "LocalVoxelsOverlay.h"
#include "ModelOverlay.h"
#include "Overlays.h"
#include "Sphere3DOverlay.h"
#include "TextOverlay.h"
#include "LocalVoxelsOverlay.h"
Overlays::Overlays() : _nextOverlayID(1) {
}
@ -156,6 +158,18 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
thisOverlay->setProperties(properties);
created = true;
is3D = true;
} else if (type == "model") {
thisOverlay = new ModelOverlay();
thisOverlay->init(_parent);
thisOverlay->setProperties(properties);
created = true;
is3D = true;
} else if (type == "billboard") {
thisOverlay = new BillboardOverlay();
thisOverlay->init(_parent);
thisOverlay->setProperties(properties);
created = true;
is3D = true;
}
if (created) {

View file

@ -137,7 +137,7 @@ background: transparent;</string>
<property name="font">
<font>
<family>Helvetica,Arial,sans-serif</family>
<pointsize>16</pointsize>
<pointsize>-1</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
@ -326,9 +326,6 @@ padding-top: 3px;</string>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="styleSheet">
<string notr="true">margin: 0;</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
@ -336,7 +333,7 @@ padding-top: 3px;</string>
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
@ -352,7 +349,7 @@ padding-top: 3px;</string>
<rect>
<x>0</x>
<y>0</y>
<width>269</width>
<width>284</width>
<height>16</height>
</rect>
</property>
@ -460,7 +457,6 @@ font: bold 16px;</string>
<string notr="true">background: transparent;
font-size: 14px;</string>
</property>
<zorder>runningScriptsList</zorder>
</widget>
</item>
</layout>
@ -627,10 +623,10 @@ QListView::item {
<enum>QFrame::Plain</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>

View file

@ -11,6 +11,7 @@
#include "NodeList.h"
#include "PacketHeaders.h"
#include "UserActivityLogger.h"
#include "DomainHandler.h"
@ -83,6 +84,7 @@ void DomainHandler::setHostname(const QString& hostname) {
qDebug("Looking up DS hostname %s.", _hostname.toLocal8Bit().constData());
QHostInfo::lookupHost(_hostname, this, SLOT(completedHostnameLookup(const QHostInfo&)));
UserActivityLogger::getInstance().changedDomain(_hostname);
emit hostnameChanged(_hostname);
}
}

View file

@ -0,0 +1,155 @@
//
// UserActivityLogger.cpp
//
//
// Created by Clement on 5/21/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "UserActivityLogger.h"
#include <QEventLoop>
#include <QJsonDocument>
#include <QHttpMultiPart>
#include <QTimer>
static const QString USER_ACTIVITY_URL = "/api/v1/user_activities";
UserActivityLogger& UserActivityLogger::getInstance() {
static UserActivityLogger sharedInstance;
return sharedInstance;
}
UserActivityLogger::UserActivityLogger() {
}
void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCallbackParameters params) {
AccountManager& accountManager = AccountManager::getInstance();
QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
// Adding the action name
QHttpPart actionPart;
actionPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"action_name\"");
actionPart.setBody(QByteArray().append(action));
multipart->append(actionPart);
// If there are action details, add them to the multipart
if (!details.isEmpty()) {
QHttpPart detailsPart;
detailsPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
" name=\"action_details\"");
detailsPart.setBody(QJsonDocument(details).toJson(QJsonDocument::Compact));
multipart->append(detailsPart);
}
qDebug() << "Logging activity" << action;
// if no callbacks specified, call our owns
if (params.isEmpty()) {
params.jsonCallbackReceiver = this;
params.jsonCallbackMethod = "requestFinished";
params.errorCallbackReceiver = this;
params.errorCallbackMethod = "requestError";
}
accountManager.authenticatedRequest(USER_ACTIVITY_URL,
QNetworkAccessManager::PostOperation,
params,
NULL,
multipart);
}
void UserActivityLogger::requestFinished(const QJsonObject& object) {
qDebug() << object;
}
void UserActivityLogger::requestError(QNetworkReply::NetworkError error,const QString& string) {
qDebug() << error << ": " << string;
}
void UserActivityLogger::launch(QString applicationVersion) {
const QString ACTION_NAME = "launch";
QJsonObject actionDetails;
QString VERSION_KEY = "version";
actionDetails.insert(VERSION_KEY, applicationVersion);
logAction(ACTION_NAME, actionDetails);
}
void UserActivityLogger::close(int delayTime) {
const QString ACTION_NAME = "close";
// In order to get the end of the session, we need to give the account manager enough time to send the packet.
QEventLoop loop;
// Here we connect the callbacks to stop the event loop
JSONCallbackParameters params;
params.jsonCallbackReceiver = &loop;
params.errorCallbackReceiver = &loop;
params.jsonCallbackMethod = "quit";
params.errorCallbackMethod = "quit";
// In case something goes wrong, we also setup a timer so that the delai is not greater than delayTime
QTimer timer;
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
// Now we can log it
logAction(ACTION_NAME, QJsonObject(), params);
timer.start(delayTime);
loop.exec();
}
void UserActivityLogger::changedDisplayName(QString displayName) {
const QString ACTION_NAME = "changed_display_name";
QJsonObject actionDetails;
const QString DISPLAY_NAME = "display_name";
actionDetails.insert(DISPLAY_NAME, displayName);
logAction(ACTION_NAME, actionDetails);
}
void UserActivityLogger::changedModel(QString typeOfModel, QString modelURL) {
const QString ACTION_NAME = "changed_model";
QJsonObject actionDetails;
const QString TYPE_OF_MODEL = "type_of_model";
const QString MODEL_URL = "model_url";
actionDetails.insert(TYPE_OF_MODEL, typeOfModel);
actionDetails.insert(MODEL_URL, modelURL);
logAction(ACTION_NAME, actionDetails);
}
void UserActivityLogger::changedDomain(QString domainURL) {
const QString ACTION_NAME = "changed_domain";
QJsonObject actionDetails;
const QString DOMAIN_URL = "domain_url";
actionDetails.insert(DOMAIN_URL, domainURL);
logAction(ACTION_NAME, actionDetails);
}
void UserActivityLogger::connectedDevice(QString typeOfDevice, QString deviceName) {
const QString ACTION_NAME = "connected_device";
QJsonObject actionDetails;
const QString TYPE_OF_DEVICE = "type_of_device";
const QString DEVICE_NAME = "device_name";
actionDetails.insert(TYPE_OF_DEVICE, typeOfDevice);
actionDetails.insert(DEVICE_NAME, deviceName);
logAction(ACTION_NAME, actionDetails);
}
void UserActivityLogger::loadedScript(QString scriptName) {
const QString ACTION_NAME = "loaded_script";
QJsonObject actionDetails;
const QString SCRIPT_NAME = "script_name";
actionDetails.insert(SCRIPT_NAME, scriptName);
logAction(ACTION_NAME, actionDetails);
}

View file

@ -0,0 +1,47 @@
//
// UserActivityLogger.h
//
//
// Created by Clement on 5/21/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_UserActivityLogger_h
#define hifi_UserActivityLogger_h
#include "AccountManager.h"
#include <QObject>
#include <QString>
#include <QJsonObject>
#include <QNetworkReply>
class UserActivityLogger : public QObject {
Q_OBJECT
public:
static UserActivityLogger& getInstance();
public slots:
void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters());
void launch(QString applicationVersion);
void close(int delayTime);
void changedDisplayName(QString displayName);
void changedModel(QString typeOfModel, QString modelURL);
void changedDomain(QString domainURL);
void connectedDevice(QString typeOfDevice, QString deviceName);
void loadedScript(QString scriptName);
private slots:
void requestFinished(const QJsonObject& object);
void requestError(QNetworkReply::NetworkError error,const QString& string);
private:
UserActivityLogger();
};
#endif // hifi_UserActivityLogger_h