[HAM] Added recording functionality. 00/81600/2
authorTomasz Marciniak <t.marciniak@samsung.com>
Tue, 19 Jul 2016 11:14:54 +0000 (13:14 +0200)
committerTomasz Marciniak <t.marciniak@samsung.com>
Wed, 27 Jul 2016 09:32:51 +0000 (11:32 +0200)
[Verification] Code compiles. TCT pass rate did not change.

Change-Id: Ib1e0475547f8fc094f647065afc129e84d8bcaac
Signed-off-by: Tomasz Marciniak <t.marciniak@samsung.com>
src/humanactivitymonitor/humanactivitymonitor_api.js
src/humanactivitymonitor/humanactivitymonitor_instance.cc
src/humanactivitymonitor/humanactivitymonitor_instance.h
src/humanactivitymonitor/humanactivitymonitor_manager.cc
src/humanactivitymonitor/humanactivitymonitor_manager.h

index d9c3bf0..2d2d65e 100755 (executable)
@@ -33,6 +33,10 @@ function SetReadOnlyProperty(obj, n, v) {
 }
 
 var ACCUMULATIVE_PEDOMETER_DATA = 'ACCUMULATIVE_PEDOMETER_DATA';
+var MIN_OPTION_INTERVAL = 0;
+var MIN_OPTION_RETENTION_PERIOD = 1;
+var MIN_QUERY_TIME = 0;
+var MIN_QUERY_INTERVAL = 0;
 
 var HumanActivityType = {
   PEDOMETER: 'PEDOMETER',
@@ -42,6 +46,13 @@ var HumanActivityType = {
   SLEEP_MONITOR: 'SLEEP_MONITOR'
 };
 
+var HumanActivityRecorderType = {
+  PEDOMETER: 'PEDOMETER',
+  HRM: 'HRM',
+  SLEEP_MONITOR: 'SLEEP_MONITOR',
+  PRESSURE: 'PRESSURE'
+};
+
 var PedometerStepStatus = {
   NOT_MOVING: 'NOT_MOVING',
   WALKING: 'WALKING',
@@ -90,6 +101,39 @@ function convertActivityData(type, data) {
   }
 }
 
+function createRecorderData(func, data) {
+  var array = [];
+
+  data.forEach(function (d) {
+    array.push(new func(d));
+  });
+
+  return array;
+}
+
+function convertActivityRecorderData(type, data) {
+  var func = undefined;
+  switch (type) {
+    case HumanActivityRecorderType.PEDOMETER:
+      func = HumanActivityRecorderPedometerData;
+      break;
+    case HumanActivityRecorderType.HRM:
+      func = HumanActivityRecorderHRMData;
+      break;
+    case HumanActivityRecorderType.SLEEP_MONITOR:
+      func = HumanActivityRecorderSleepMonitorData;
+      break;
+    case HumanActivityRecorderType.PRESSURE:
+      func = HumanActivityRecorderPressureData;
+      break;
+    default:
+      console.error('Uknown human activity recorder type: ' + type);
+      return;
+  }
+
+  return createRecorderData(func, data);
+}
+
 function ActivityRecognitionListenerManager() {
   this.listeners = {};
   this.nextId = 1;
@@ -386,6 +430,87 @@ HumanActivityMonitorManager.prototype.removeActivityRecognitionListener = functi
   activityRecognitionListener.removeListener(args.watchId);
 };
 
+HumanActivityMonitorManager.prototype.startRecorder = function() {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)},
+    {name: 'options', type : types_.DICTIONARY, optional: true, nullable: false}
+  ]);
+
+  var callArgs = {};
+
+  if (args.options) {
+    if (MIN_OPTION_INTERVAL > args.options.interval ||
+        MIN_OPTION_RETENTION_PERIOD > args.options.interval) {
+      throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid option value');
+    }
+
+    callArgs.options = args.options;
+  }
+
+  callArgs.type = args.type;
+
+  var result = native_.callSync('HumanActivityMonitorManager_startRecorder', callArgs);
+
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+};
+
+HumanActivityMonitorManager.prototype.stopRecorder = function() {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)},
+  ]);
+
+  var callArgs = {};
+  callArgs.type = args.type;
+
+  var result = native_.callSync('HumanActivityMonitorManager_stopRecorder', callArgs);
+
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+};
+
+HumanActivityMonitorManager.prototype.readRecorderData = function() {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)},
+    {name: 'query', type : types_.DICTIONARY, optional: false, nullable: true},
+    {name: 'successCallback', type: types_.FUNCTION},
+    {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
+  ]);
+
+  var callArgs = {};
+
+  if (args.query) {
+    if ((args.query.startTime && MIN_QUERY_TIME > args.query.startTime) ||
+        (args.query.endTime && MIN_QUERY_TIME > args.query.endTime) ||
+        (args.query.anchorTime && MIN_QUERY_TIME > args.query.anchorTime) ||
+        (args.query.interval && MIN_QUERY_INTERVAL > args.query.interval) ||
+        (args.query.startTime && args.query.endTime && args.query.startTime > args.query.endTime)) {
+      throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid query value');
+    }
+  }
+
+  callArgs.options = args.options;
+  callArgs.type = args.type;
+  callArgs.query = args.query;
+
+  var callback = function(result) {
+    if (native_.isFailure(result)) {
+        native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+    } else {
+        var array = convertActivityRecorderData(args.type, native_.getResultObject(result));
+        args.successCallback(array);
+    }
+  };
+
+  var result = native_.call('HumanActivityMonitorManager_readRecorderData', callArgs, callback);
+
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+};
+
 function StepDifference(data) {
   SetReadOnlyProperty(this, 'stepCountDifference', data.stepCountDifference);
   SetReadOnlyProperty(this, 'timestamp', data.timestamp);
@@ -480,4 +605,50 @@ function HumanActivitySleepMonitorData(data) {
 HumanActivitySleepMonitorData.prototype = new HumanActivityData();
 HumanActivitySleepMonitorData.prototype.constructor = HumanActivitySleepMonitorData;
 
+//Recorded data
+function HumanActivityRecorderData(data) {
+  if (data) {
+    SetReadOnlyProperty(this, 'startTime', data.startTime);
+    SetReadOnlyProperty(this, 'endTime', data.endTime);
+  }
+}
+
+function HumanActivityRecorderPedometerData(data) {
+  HumanActivityRecorderData.call(this, data);
+  SetReadOnlyProperty(this, 'distance', data.distance);
+  SetReadOnlyProperty(this, 'calorie', data.calorie);
+  SetReadOnlyProperty(this, 'totalStepCount', data.totalStepCount);
+  SetReadOnlyProperty(this, 'walkStepCount', data.walkStepCount);
+  SetReadOnlyProperty(this, 'runStepCount', data.runStepCount);
+}
+
+HumanActivityRecorderPedometerData.prototype = new HumanActivityRecorderData();
+HumanActivityRecorderPedometerData.prototype.constructor = HumanActivityRecorderPedometerData;
+
+function HumanActivityRecorderHRMData(data) {
+  HumanActivityRecorderData.call(this, data);
+  SetReadOnlyProperty(this, 'heartRate', data.heartRate);
+}
+
+HumanActivityRecorderHRMData.prototype = new HumanActivityRecorderData();
+HumanActivityRecorderHRMData.prototype.constructor = HumanActivityRecorderHRMData;
+
+function HumanActivityRecorderSleepMonitorData(data) {
+  HumanActivityRecorderData.call(this, data);
+  SetReadOnlyProperty(this, 'status', data.status);
+}
+
+HumanActivityRecorderSleepMonitorData.prototype = new HumanActivityRecorderData();
+HumanActivityRecorderSleepMonitorData.prototype.constructor = HumanActivityRecorderSleepMonitorData;
+
+function HumanActivityRecorderPressureData(data) {
+  HumanActivityRecorderData.call(this, data);
+  SetReadOnlyProperty(this, 'max', data.max);
+  SetReadOnlyProperty(this, 'min', data.min);
+  SetReadOnlyProperty(this, 'average', data.average);
+}
+
+HumanActivityRecorderPressureData.prototype = new HumanActivityRecorderData();
+HumanActivityRecorderPressureData.prototype.constructor = HumanActivityRecorderPressureData;
+
 exports = new HumanActivityMonitorManager();
index d572ba3..5000cb4 100755 (executable)
@@ -35,6 +35,8 @@ namespace {
 const std::string kPrivilegeHealthInfo = "http://tizen.org/privilege/healthinfo";
 const std::string kPrivilegeLocation = "http://tizen.org/privilege/location";
 
+const int DEFAULT_HRM_INTERVAL = 1440;  // 1440 (1 day) default value for HRM's interval
+const int DEFAULT_RETENTION_PERIOD = 1; // 1 hour default value for retention period
 }  // namespace
 
 using common::PlatformResult;
@@ -58,6 +60,12 @@ HumanActivityMonitorInstance::HumanActivityMonitorInstance() {
                 HumanActivityMonitorManagerAddActivityRecognitionListener);
   REGISTER_SYNC("HumanActivityMonitorManager_removeActivityRecognitionListener",
                 HumanActivityMonitorManagerRemoveActivityRecognitionListener);
+  REGISTER_SYNC("HumanActivityMonitorManager_startRecorder",
+                HumanActivityMonitorManagerStartRecorder);
+  REGISTER_SYNC("HumanActivityMonitorManager_stopRecorder",
+                HumanActivityMonitorManagerStopRecorder);
+  REGISTER_SYNC("HumanActivityMonitorManager_readRecorderData",
+                 HumanActivityMonitorManagerReadRecorderData);
 #undef REGISTER_SYNC
 }
 
@@ -261,6 +269,111 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerRemoveActivityReco
   }
 }
 
+void HumanActivityMonitorInstance::HumanActivityMonitorManagerStartRecorder(
+    const picojson::value& args, picojson::object& out) {
+  LoggerD("Enter");
+
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeHealthInfo, &out);
+  CHECK_EXIST(args, "type", out)
+
+  const auto& type = args.get("type").get<std::string>();
+
+  PlatformResult result = Init();
+  if (!result) {
+    LogAndReportError(result, &out, ("Failed: Init()"));
+    return;
+  }
+
+  int interval = DEFAULT_HRM_INTERVAL;
+  int retention_period = DEFAULT_RETENTION_PERIOD;
+
+  if (args.contains("options")) {
+    const auto& options = args.get("options");
+    auto& js_interval = options.get("interval");
+    auto& js_retention_period = options.get("retentionPeriod");
+
+    if (js_interval.is<double>()) {
+      interval = js_interval.get<double>();
+    }
+
+    if (js_retention_period.is<double>()) {
+      retention_period = js_retention_period.get<double>();
+    }
+  }
+
+  LoggerD("interval: %d retentionPeriod: %d", interval, retention_period);
+
+  result = manager_->StartDataRecorder(type, interval, retention_period);
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out, ("Failed: manager_->StartDataRecorder()"));
+  }
+}
+
+void HumanActivityMonitorInstance::HumanActivityMonitorManagerStopRecorder(
+    const picojson::value& args, picojson::object& out) {
+  LoggerD("Enter");
+  CHECK_EXIST(args, "type", out)
+
+  const auto& type = args.get("type").get<std::string>();
+
+  PlatformResult result = Init();
+  if (!result) {
+    LogAndReportError(result, &out, ("Failed: Init()"));
+    return;
+  }
+
+  result = manager_->StopDataRecorder(type);
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out, ("Failed: manager_->StopDataRecorder()"));
+  }
+}
+
+void HumanActivityMonitorInstance::HumanActivityMonitorManagerReadRecorderData(
+    const picojson::value& args, picojson::object& out) {
+  LoggerD("Enter");
+  CHECK_EXIST(args, "type", out)
+  CHECK_EXIST(args, "query", out)
+
+  const auto& type = args.get("type").get<std::string>();
+  const auto& query = args.get("query");
+
+  PlatformResult result = Init();
+  if (!result) {
+    LogAndReportError(result, &out, ("Failed: Init()"));
+    return;
+  }
+
+  const auto callback_id = args.get("callbackId").get<double>();
+
+  auto get = [this, type, query, callback_id]() -> void {
+    picojson::value response = picojson::value(picojson::object());
+    picojson::object& response_obj = response.get<picojson::object>();
+    response_obj["callbackId"] = picojson::value(callback_id);
+
+    //picojson::value data = picojson::value();
+    picojson::value array_value{picojson::array{}};
+    auto* array = &array_value.get<picojson::array>();
+
+    PlatformResult result = manager_->ReadRecorderData(type, array, query);
+
+    if (result) {
+      ReportSuccess(array_value, response_obj);
+    } else {
+      LogAndReportError(result, &response_obj, ("Failed: manager_->ReadRecorderData()"));
+    }
+
+    Instance::PostMessage(this, response.serialize().c_str());
+  };
+
+  TaskQueue::GetInstance().Async(get);
+
+  ReportSuccess(out);
+}
+
 #undef CHECK_EXIST
 
 }  // namespace humanactivitymonitor
index 07f0e1a..1ab6829 100755 (executable)
@@ -42,6 +42,12 @@ class HumanActivityMonitorInstance : public common::ParsedInstance {
       const picojson::value& args, picojson::object& out);
   void HumanActivityMonitorManagerRemoveActivityRecognitionListener(
       const picojson::value& args, picojson::object& out);
+  void HumanActivityMonitorManagerStartRecorder(
+      const picojson::value& args, picojson::object& out);
+  void HumanActivityMonitorManagerStopRecorder(
+      const picojson::value& args, picojson::object& out);
+  void HumanActivityMonitorManagerReadRecorderData(
+      const picojson::value& args, picojson::object& out);
 
   std::shared_ptr<HumanActivityMonitorManager> manager_;
   common::PlatformResult Init();
index 284a686..387220f 100755 (executable)
 #include <sensor.h>
 #include <sensor_internal.h>
 #include <system_info.h>
+#include <mutex>
 
 #include "common/logger.h"
 #include "common/optional.h"
 #include "common/picojson.h"
 #include "common/tools.h"
+#include "common/scope_exit.h"
 
 namespace extension {
 namespace humanactivitymonitor {
@@ -36,12 +38,16 @@ using common::ErrorCode;
 using common::tools::ReportError;
 using common::tools::ReportSuccess;
 
+typedef std::map<sensor_recorder_data_e, const std::string&> SensorRecorderDataMap;
+typedef std::map<sensor_recorder_query_e, const std::string&> SensorRecorderQueryMap;
+
 namespace {
 
 const std::string kActivityTypePedometer = "PEDOMETER";
 const std::string kActivityTypeWristUp = "WRIST_UP";
 const std::string kActivityTypeHrm = "HRM";
 const std::string kActivityTypeSleepMonitor = "SLEEP_MONITOR";
+const std::string kActivityTypePressure = "PRESSURE";
 
 const std::string kSleepStateAwake = "AWAKE";
 const std::string kSleepStateAsleep = "ASLEEP";
@@ -70,6 +76,46 @@ const std::string kAccumulativeTotalStepCount = "accumulativeTotalStepCount";
 const std::string kAccumulativeWalkStepCount = "accumulativeWalkStepCount";
 const std::string kAccumulativeRunStepCount = "accumulativeRunStepCount";
 
+const std::string kRecordedStartTime = "startTime";
+const std::string kRecordedEndTime = "endTime";
+const std::string kRecordedHeartRate = "heartRate";
+
+const std::string kRecordedDistance = "distance";
+const std::string kRecordedCalorie = "calorie";
+const std::string kRecordedTotalStepCount = "totalStepCount";
+const std::string kRecordedWalkStepCount = "walkStepCount";
+const std::string kRecordedRunStepCount = "runStepCount";
+
+const std::string kRecordedMin = "min";
+const std::string kRecordedMax = "max";
+const std::string kRecordedAverage = "average";
+
+const std::string kRecordedAnchorTime = "anchorTime";
+const std::string kRecordedInterval = "interval";
+
+ErrorCode getErrorCode (const int errorCode) {
+  ScopeLogger();
+  switch (errorCode) {
+    case SENSOR_ERROR_IO_ERROR:
+      return ErrorCode::IO_ERR;
+    case SENSOR_ERROR_NOT_SUPPORTED:
+      return ErrorCode::NOT_SUPPORTED_ERR;
+    case SENSOR_ERROR_PERMISSION_DENIED:
+      return ErrorCode::PERMISSION_DENIED_ERR;
+    case SENSOR_ERROR_NOT_AVAILABLE:
+      return ErrorCode::SERVICE_NOT_AVAILABLE_ERR;
+    case SENSOR_ERROR_NO_DATA:
+      return ErrorCode::NOT_FOUND_ERR;
+    case SENSOR_ERROR_INVALID_PARAMETER:
+      return ErrorCode::INVALID_VALUES_ERR;
+    case SENSOR_ERROR_OUT_OF_MEMORY:
+    case SENSOR_ERROR_OPERATION_FAILED:
+    case SENSOR_ERROR_NOT_NEED_CALIBRATION:
+    default:
+      return ErrorCode::ABORT_ERR;
+  }
+}
+
 // helper structure, allows easier access to data values
 struct PedometerDataWrapper : public sensor_pedometer_data_t {
   inline float steps() const {
@@ -155,6 +201,66 @@ std::string FromSensorPedometerState(sensor_pedometer_state_e e) {
   }
 }
 
+PlatformResult ConvertRecordedTime(void* data, picojson::object* obj) {
+  ScopeLogger("convert_recorded_time");
+
+  time_t start_time, end_time;
+
+  int ret = sensor_recorder_data_get_time(data, &start_time, &end_time);
+  if (SENSOR_ERROR_NONE != ret) {
+    return LogAndCreateResult(getErrorCode(ret),
+                                    "Failed to get time",
+                                    ("Failed to get time, error: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  obj->insert(std::make_pair(kRecordedStartTime, picojson::value(static_cast<double>(start_time))));
+  obj->insert(std::make_pair(kRecordedEndTime, picojson::value(static_cast<double>(end_time))));
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult ConvertRecordedInt(void* data, picojson::object* obj,
+                                  const SensorRecorderDataMap& map) {
+  ScopeLogger();
+
+  int ret = SENSOR_ERROR_NONE;
+  int tmp = 0;
+
+  for (auto& it : map) {
+    ret = sensor_recorder_data_get_int(data, it.first, &tmp);
+    if (SENSOR_ERROR_NONE != ret) {
+      return LogAndCreateResult(getErrorCode(ret),
+                                      "Failed to get int value",
+                                      ("Failed to get int value, error: %d (%s)", ret, get_error_message(ret)));
+    }
+
+    obj->insert(std::make_pair(it.second, picojson::value(static_cast<double>(tmp))));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult ConvertRecordedDouble(void* data, picojson::object* obj,
+                                     const SensorRecorderDataMap& map) {
+  ScopeLogger();
+
+  int ret = SENSOR_ERROR_NONE;
+  double tmp = 0;
+
+  for (auto& it : map) {
+    ret = sensor_recorder_data_get_double(data, it.first, &tmp);
+    if (SENSOR_ERROR_NONE != ret) {
+      return LogAndCreateResult(getErrorCode(ret),
+                                      "Failed to get double value",
+                                      ("Failed to get double value, error: %d (%s)", ret, get_error_message(ret)));
+    }
+
+    obj->insert(std::make_pair(it.second, picojson::value(static_cast<double>(tmp))));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 }  // namespace
 
 const std::string kActivityTypeGps = "GPS";
@@ -227,6 +333,34 @@ class HumanActivityMonitorManager::Monitor {
     return GetDataImpl(data);
   }
 
+  PlatformResult StartDataRecorder(int interval, int retention_period) {
+    ScopeLogger(type());
+
+    auto result = IsSupported();
+    if (!result) {
+      return result;
+    }
+
+    return StartDataRecorderImpl(interval, retention_period);
+  }
+
+  PlatformResult StopDataRecorder() {
+    ScopeLogger(type());
+
+    return StopDataRecorderImpl();
+  }
+
+  PlatformResult ReadRecorderData(picojson::array* data, const picojson::value& query) {
+    ScopeLogger(type());
+
+    auto result = IsSupported();
+    if (!result) {
+      return result;
+    }
+
+    return ReadRecorderDataImpl(data, query);
+  }
+
  protected:
   virtual PlatformResult IsSupportedImpl(bool* supported) const {
     ScopeLogger(type());
@@ -249,6 +383,21 @@ class HumanActivityMonitorManager::Monitor {
     return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR,"NOT_SUPPORTED_ERR");
   }
 
+  virtual PlatformResult StartDataRecorderImpl(int interval, int retention_period) const {
+    ScopeLogger(type());
+    return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR,"NOT_SUPPORTED_ERR");
+  }
+
+  virtual PlatformResult StopDataRecorderImpl() const {
+    ScopeLogger(type());
+    return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR,"NOT_SUPPORTED_ERR");
+  }
+
+  virtual PlatformResult ReadRecorderDataImpl(picojson::array* data, const picojson::value& query) {
+    ScopeLogger(type());
+    return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR,"NOT_SUPPORTED_ERR");
+  }
+
  private:
   PlatformResult IsSupported() {
     ScopeLogger(type());
@@ -383,8 +532,10 @@ class HumanActivityMonitorManager::Monitor::GestureMonitor : public HumanActivit
 class HumanActivityMonitorManager::Monitor::SensorMonitor : public HumanActivityMonitorManager::Monitor {
  public:
   using SensorEventConverter = std::function<PlatformResult(sensor_event_s* event, picojson::object* o)>;
+  using SensorRecordedConverter = std::function<PlatformResult(void* data, picojson::object* o)>;
 
-  SensorMonitor(const std::string& t, sensor_type_e s, const SensorEventConverter& c) : Monitor(t), sensor_(s), handle_(nullptr), converter_(c) {
+  SensorMonitor(const std::string& t, sensor_type_e s, const SensorEventConverter& c, const SensorRecordedConverter& r)
+    : Monitor(t), sensor_(s), handle_(nullptr), converter_(c), converter_recorded_(r), recorded_data_(nullptr) {
     ScopeLogger(type());
   }
 
@@ -522,6 +673,90 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor : public HumanActivity
     return PlatformResult(ErrorCode::NO_ERROR);
   }
 
+  virtual PlatformResult StartDataRecorderImpl(int interval, int retention_period) const override {
+    ScopeLogger(type());
+
+    sensor_recorder_option_h option = nullptr;
+
+    int ret = sensor_recorder_create_option(&option);
+    if (SENSOR_ERROR_NONE != ret) {
+      return LogAndCreateResult(getErrorCode(ret),
+                                "Failed to create recorder option",
+                                ("Failed to create (%d) recorder option, error: %d (%s)", sensor_, ret, get_error_message(ret)));
+    }
+
+    SCOPE_EXIT {
+      sensor_recorder_destroy_option(option);
+    };
+
+    auto result = SetOptions(&option, interval, retention_period);
+    if (!result) {
+      return result;
+    }
+
+    ret = sensor_recorder_start(sensor_, option);
+    if (SENSOR_ERROR_NONE != ret) {
+      return LogAndCreateResult(getErrorCode(ret),
+                                "Failed to start recording",
+                                ("Failed to start (%d) recording, error: %d (%s)", sensor_, ret, get_error_message(ret)));
+    }
+
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  virtual PlatformResult StopDataRecorderImpl() const override {
+    ScopeLogger(type());
+
+    int ret = sensor_recorder_stop(sensor_);
+    if (SENSOR_ERROR_NONE != ret) {
+      return LogAndCreateResult(getErrorCode(ret),
+                                "Failed to stop recording",
+                                ("Failed to stop (%d) recording, error: %d (%s)", sensor_, ret, get_error_message(ret)));
+    }
+
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  virtual PlatformResult ReadRecorderDataImpl(picojson::array* data, const picojson::value& query) override {
+    ScopeLogger(type());
+
+    std::lock_guard<std::mutex> lock(mutex_);
+    this->recorded_data_ = data;
+
+    sensor_recorder_query_h query_h = nullptr;
+    int ret = sensor_recorder_create_query(&query_h);
+    if (SENSOR_ERROR_NONE != ret) {
+      return LogAndCreateResult(getErrorCode(ret),
+                                "Failed to create query",
+                                ("Failed to create (%d) query, error: %d (%s)", sensor_, ret, get_error_message(ret)));
+    }
+
+    SCOPE_EXIT {
+      sensor_recorder_destroy_query(query_h);
+    };
+
+    if (!query.is<picojson::null>()) {
+      auto result = SetQuery(&query_h, query);
+      if (!result) {
+        return result;
+      }
+    }
+
+    ret = sensor_recorder_read_sync(sensor_, query_h, SensorRecordedDataCb, static_cast<void*>(this));
+    if (SENSOR_ERROR_NONE != ret) {
+      return LogAndCreateResult(getErrorCode(ret),
+                                "Failed to read recorded data",
+                                ("Failed to read (%d) recorded data, error: %d (%s)", sensor_, ret, get_error_message(ret)));
+    }
+
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  void addRecordedData(picojson::value* data) {
+    ScopeLogger();
+    recorded_data_->push_back(*data);
+  }
+
  private:
   static void OnSensorEvent(sensor_h, sensor_event_s* event, void* user_data) {
     ScopeLogger();
@@ -545,9 +780,89 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor : public HumanActivity
     callback(&sensor_data);
   }
 
+  static bool SensorRecordedDataCb(sensor_type_e type, void* data, int remains,
+                                   sensor_error_e error, void* user_data) {
+    ScopeLogger();
+
+    auto monitor = static_cast<SensorMonitor*>(user_data);
+
+    picojson::value val = picojson::value(picojson::object());
+    picojson::object* obj = &val.get<picojson::object>();
+
+    auto result = monitor->converter_recorded_(data, obj);
+    if (result) {
+      monitor->addRecordedData(&val);
+    }
+
+    return true; // continue
+  }
+
+  PlatformResult SetOptions(sensor_recorder_option_h *option,
+                            int interval, int retention_period) const {
+    ScopeLogger();
+
+    int ret = SENSOR_ERROR_NONE;
+
+    if (SENSOR_HRM == sensor_) {
+      ret = sensor_recorder_option_set_int(
+          *option, SENSOR_RECORDER_OPTION_INTERVAL, interval);
+
+      if (SENSOR_ERROR_NONE != ret) {
+        return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                                  "Failed to set recorder option",
+                                  ("Failed to set (%d) recorder option, error: %d (%s)", sensor_, ret, get_error_message(ret)));
+      }
+    }
+
+    ret = sensor_recorder_option_set_int(
+        *option, SENSOR_RECORDER_OPTION_RETENTION_PERIOD, retention_period);
+    if (SENSOR_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                                "Failed to set recorder option",
+                                ("Failed to set (%d) recorder option, error: %d (%s)", sensor_, ret, get_error_message(ret)));
+    }
+
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  PlatformResult SetQuery(sensor_recorder_query_h *query_h,
+                          const picojson::value& query) const {
+    ScopeLogger();
+
+    SensorRecorderQueryMap map_query {
+      {SENSOR_RECORDER_QUERY_START_TIME, kRecordedStartTime},
+      {SENSOR_RECORDER_QUERY_END_TIME, kRecordedEndTime},
+    };
+
+    if (SENSOR_HUMAN_PEDOMETER == sensor_ || SENSOR_PRESSURE == sensor_) {
+      map_query.insert(std::make_pair(SENSOR_RECORDER_QUERY_ANCHOR_TIME, kRecordedAnchorTime));
+      map_query.insert(std::make_pair(SENSOR_RECORDER_QUERY_TIME_INTERVAL, kRecordedInterval));
+    }
+
+    for (auto& it : map_query) {
+      int val = -1;
+      if (query.get(it.second).is<double>()) {
+        val = query.get(it.second).get<double>();
+        if (0 <= val) {
+          int ret = sensor_recorder_query_set_time(query_h, it.first, val);
+          if (SENSOR_ERROR_NONE != ret) {
+            return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                                      "Failed to set query parameter",
+                                      ("Failed to set (%d) query parameter, error: %d (%s)", sensor_, ret, get_error_message(ret)));
+          }
+        }
+      }
+    }
+
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
   sensor_type_e sensor_;
   sensor_listener_h handle_;
   SensorEventConverter converter_;
+  SensorRecordedConverter converter_recorded_;
+  picojson::array* recorded_data_;
+  std::mutex mutex_;
 };
 
 class HumanActivityMonitorManager::Monitor::GpsMonitor : public HumanActivityMonitorManager::Monitor {
@@ -1089,11 +1404,86 @@ HumanActivityMonitorManager::HumanActivityMonitorManager()
     return PlatformResult(ErrorCode::NO_ERROR);
   };
 
-  monitors_.insert(std::make_pair(kActivityTypePedometer, std::make_shared<Monitor::SensorMonitor>(kActivityTypePedometer, SENSOR_HUMAN_PEDOMETER, convert_pedometer)));
+  auto convert_recorded_pedometer = [](void* data, picojson::object* obj) -> PlatformResult {
+    ScopeLogger("convert_recorded_pedometer");
+
+    SensorRecorderDataMap map_int {
+      {SENSOR_RECORDER_DATA_STEPS, kRecordedTotalStepCount},
+      {SENSOR_RECORDER_DATA_WALK_STEPS, kRecordedWalkStepCount},
+      {SENSOR_RECORDER_DATA_RUN_STEPS, kRecordedRunStepCount}
+    };
+
+    SensorRecorderDataMap map_double {
+      {SENSOR_RECORDER_DATA_DISTANCE, kRecordedDistance},
+      {SENSOR_RECORDER_DATA_CALORIE, kRecordedCalorie}
+    };
+
+    auto result = ConvertRecordedInt(data, obj, map_int);
+    if (!result) {
+      return result;
+    }
+
+    result = ConvertRecordedDouble(data, obj, map_double);
+    if (!result) {
+      return result;
+    }
+
+    return ConvertRecordedTime(data, obj);
+  };
+
+  auto convert_recorded_hrm = [](void* data, picojson::object* obj) -> PlatformResult {
+    ScopeLogger("convert_recorded_hrm");
+
+    SensorRecorderDataMap map_int {
+      {SENSOR_RECORDER_DATA_HEART_RATE, kRecordedHeartRate},
+    };
+
+    auto result = ConvertRecordedInt(data, obj, map_int);
+    if (!result) {
+      return result;
+    }
+
+    return ConvertRecordedTime(data, obj);
+  };
+
+  auto convert_recorded_sleep_monitor = [](void* data, picojson::object* obj) -> PlatformResult {
+    ScopeLogger("convert_recorded_sleep_monitor");
+
+    SensorRecorderDataMap map_int {
+      {SENSOR_RECORDER_DATA_SLEEP_STATE, kStatus}
+    };
+
+    auto result = ConvertRecordedInt(data, obj, map_int);
+    if (!result) {
+      return result;
+    }
+
+    return ConvertRecordedTime(data, obj);
+  };
+
+  auto convert_recorded_pressure = [](void* data, picojson::object* obj) -> PlatformResult {
+    ScopeLogger("convert_recorded_pressure");
+
+    SensorRecorderDataMap map_double {
+      {SENSOR_RECORDER_DATA_MAX_PRESSURE, kRecordedMax},
+      {SENSOR_RECORDER_DATA_MIN_PRESSURE, kRecordedMin},
+      {SENSOR_RECORDER_DATA_AVERAGE_PRESSURE, kRecordedAverage}
+    };
+
+    auto result = ConvertRecordedDouble(data, obj, map_double);
+    if (!result) {
+      return result;
+    }
+
+    return ConvertRecordedTime(data, obj);
+  };
+
+  monitors_.insert(std::make_pair(kActivityTypePedometer, std::make_shared<Monitor::SensorMonitor>(kActivityTypePedometer, SENSOR_HUMAN_PEDOMETER, convert_pedometer, convert_recorded_pedometer)));
   monitors_.insert(std::make_pair(kActivityTypeWristUp, std::make_shared<Monitor::GestureMonitor>(kActivityTypeWristUp)));
-  monitors_.insert(std::make_pair(kActivityTypeHrm, std::make_shared<Monitor::SensorMonitor>(kActivityTypeHrm, SENSOR_HRM, convert_hrm)));
+  monitors_.insert(std::make_pair(kActivityTypeHrm, std::make_shared<Monitor::SensorMonitor>(kActivityTypeHrm, SENSOR_HRM, convert_hrm, convert_recorded_hrm)));
   monitors_.insert(std::make_pair(kActivityTypeGps, std::make_shared<Monitor::GpsMonitor>(kActivityTypeGps)));
-  monitors_.insert(std::make_pair(kActivityTypeSleepMonitor, std::make_shared<Monitor::SensorMonitor>(kActivityTypeSleepMonitor, SENSOR_HUMAN_SLEEP_MONITOR, convert_sleep)));
+  monitors_.insert(std::make_pair(kActivityTypeSleepMonitor, std::make_shared<Monitor::SensorMonitor>(kActivityTypeSleepMonitor, SENSOR_HUMAN_SLEEP_MONITOR, convert_sleep, convert_recorded_sleep_monitor)));
+  monitors_.insert(std::make_pair(kActivityTypePressure, std::make_shared<Monitor::SensorMonitor>(kActivityTypePressure, SENSOR_PRESSURE, nullptr, convert_recorded_pressure)));
 }
 
 HumanActivityMonitorManager::~HumanActivityMonitorManager() {
@@ -1135,6 +1525,23 @@ PlatformResult HumanActivityMonitorManager::RemoveActivityRecognitionListener(co
   return activity_recognition_->RemoveListener(watch_id);
 }
 
+PlatformResult HumanActivityMonitorManager::StartDataRecorder(const std::string& type,
+    int interval, int retention_period) {
+  ScopeLogger();
+  return GetMonitor(type)->StartDataRecorder(interval, retention_period);
+}
+
+PlatformResult HumanActivityMonitorManager::StopDataRecorder(const std::string& type) {
+  ScopeLogger();
+  return GetMonitor(type)->StopDataRecorder();
+}
+
+PlatformResult HumanActivityMonitorManager::ReadRecorderData(
+    const std::string& type, picojson::array* data, const picojson::value& query) {
+  ScopeLogger();
+  return GetMonitor(type)->ReadRecorderData(data, query);
+}
+
 std::shared_ptr<HumanActivityMonitorManager::Monitor> HumanActivityMonitorManager::GetMonitor(const std::string& type) {
   ScopeLogger();
 
index ffa858f..caca7a3 100755 (executable)
@@ -49,6 +49,12 @@ class HumanActivityMonitorManager {
                                                         JsonCallback callback,
                                                         long* watch_id);
   common::PlatformResult RemoveActivityRecognitionListener(const long watchId);
+  common::PlatformResult StartDataRecorder(const std::string& type,
+                                           int interval, int retention_period);
+  common::PlatformResult StopDataRecorder(const std::string& type);
+  common::PlatformResult ReadRecorderData(const std::string& type,
+                                          picojson::array* data,
+                                          const picojson::value& query);
 
  private:
   class Monitor;