[HAM] - API for Activity Recognition added
authorAndrzej Popowski <a.popowski@samsung.com>
Thu, 11 Feb 2016 08:23:45 +0000 (09:23 +0100)
committerAndrzej Popowski <a.popowski@samsung.com>
Thu, 11 Feb 2016 13:22:24 +0000 (14:22 +0100)
Change-Id: Iae19d0ed121db5b8c9c94b1dbb0c916b378c9830
Signed-off-by: Andrzej Popowski <a.popowski@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 5e2e0ac..2c4dca9 100755 (executable)
@@ -45,6 +45,19 @@ var PedometerStepStatus = {
   RUNNING: 'RUNNING'
 };
 
+var ActivityRecognitionType = {
+  STATIONARY: 'STATIONARY',
+  WALKING: 'WALKING',
+  RUNNING: 'RUNNING',
+  IN_VEHICLE: 'IN_VEHICLE'
+};
+
+var ActivityAccuracy = {
+  LOW: 'LOW',
+  MEDIUM: 'MEDIUM',
+  HIGH: 'HIGH'
+};
+
 function convertActivityData(type, data) {
   switch (type) {
     case HumanActivityType.PEDOMETER:
@@ -63,6 +76,57 @@ function convertActivityData(type, data) {
   }
 }
 
+function ActivityRecognitionListenerManager() {
+  this.listeners = {};
+  this.nextId = 1;
+  this.nativeSet = false;
+  this.native = native_;
+  this.listenerName = 'ActivityRecognitionListener';
+};
+
+ActivityRecognitionListenerManager.prototype.onListener = function(data) {
+  var watchId = data.watchId;
+
+  if (this.listeners[watchId]) {
+    if (native_.isFailure(data)) {
+      native_.callIfPossible(this.listeners[watchId].errorCallback, native_.getErrorObject(data));
+      return;
+    }
+
+    native_.callIfPossible(
+        this.listeners[watchId].listener,
+        new HumanActivityRecognitionData(native_.getResultObject(data)));
+  }
+};
+
+ActivityRecognitionListenerManager.prototype.addListener = function(watchId, listener, errorCallback) {
+  this.listeners[watchId] = {
+    listener: listener,
+    errorCallback: errorCallback
+  };
+
+  if (!this.nativeSet) {
+    this.native.addListener(this.listenerName, this.onListener.bind(this));
+    this.nativeSet = true;
+  }
+};
+
+ActivityRecognitionListenerManager.prototype.removeListener = function(watchId) {
+  if (this.listeners[watchId] === null || this.listeners[watchId] === undefined) {
+    throw new WebAPIException(0, 'Listener id not found.', 'InvalidValuesError');
+  }
+
+  if (this.listeners.hasOwnProperty(watchId)) {
+    delete this.listeners[watchId];
+    if (type_.isEmptyObject(this.listeners)) {
+      this.native.removeListener(this.listenerName);
+      this.nativeSet = false;
+    }
+  }
+};
+
+var activityRecognitionListener = new ActivityRecognitionListenerManager();
+
 function HumanActivityMonitorManager() {
 }
 
@@ -160,7 +224,7 @@ HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
       throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR,
                                 'sampleInterval is out of range');
     }
-    break
+    break;
   case HumanActivityType.HRM:
     callbackInterval = !type_.isNullOrUndefined(args.option) ?
         args.option.callbackInterval : 100;
@@ -168,7 +232,7 @@ HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
       throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR,
                                 'callbackInterval is out of range');
     }
-    break
+    break;
   }
 
   console.log("callbackInterval = " + callbackInterval + ", sampleInterval = " + sampleInterval);
@@ -218,6 +282,45 @@ HumanActivityMonitorManager.prototype.unsetAccumulativePedometerListener = funct
                {});
 };
 
+
+HumanActivityMonitorManager.prototype.addActivityRecognitionListener = function() {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'type', type: types_.ENUM, values: Object.keys(ActivityRecognitionType)},
+    {name: 'listener', type: types_.FUNCTION},
+    {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
+  ]);
+
+
+  var result = native_.call(
+                  'HumanActivityMonitorManager_addActivityRecognitionListener',
+                  { type: args.type,
+                    listenerId: activityRecognitionListener.listenerName });
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+
+  var watchId = result.watchId;
+  activityRecognitionListener.addListener(watchId, args.listener, args.errorCallback);
+
+  return watchId;
+};
+
+HumanActivityMonitorManager.prototype.removeActivityRecognitionListener = function() {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'watchId', type: types_.ENUM},
+    {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
+  ]);
+
+  var result = native_.call(
+                  'HumanActivityMonitorManager_removeActivityRecognitionListener',
+                  { watchId: args.watchId });
+  if (native_.isFailure(result)) {
+    setTimeout(function () { native_.callIfPossible(args.errorCallback, native_.getErrorObject(result)); }, 0);
+    return;
+  }
+  activityRecognitionListener.removeListener(watchId);
+};
+
 function StepDifference() {
   SetReadOnlyProperty(this, 'stepCountDifference', null);
   SetReadOnlyProperty(this, 'timestamp', null);
@@ -268,6 +371,14 @@ function HumanActivityHRMData(data) {
 HumanActivityHRMData.prototype = new HumanActivityData();
 HumanActivityHRMData.prototype.constructor = HumanActivityHRMData;
 
+function HumanActivityRecognitionData(data) {
+  SetReadOnlyProperty(this, 'type', data.type);
+  SetReadOnlyProperty(this, 'timestamp', data.timestamp);
+  SetReadOnlyProperty(this, 'accuracy', data.accuracy);
+}
+
+HumanActivityRecognitionData.prototype = new HumanActivityData();
+HumanActivityRecognitionData.prototype.constructor = HumanActivityRecognitionData;
 
 function HumanActivityGPSInfo(data) {
   SetReadOnlyProperty(this, 'latitude', data.latitude);
index 2b6ca22..eb85ea2 100755 (executable)
@@ -58,6 +58,10 @@ HumanActivityMonitorInstance::HumanActivityMonitorInstance() {
                 HumanActivityMonitorManagerSetAccumulativePedometerListener);
   REGISTER_SYNC("HumanActivityMonitorManager_unsetAccumulativePedometerListener",
                 HumanActivityMonitorManagerUnsetAccumulativePedometerListener);
+  REGISTER_SYNC("HumanActivityMonitorManager_addActivityRecognitionListener",
+                HumanActivityMonitorManagerAddActivityRecognitionListener);
+  REGISTER_SYNC("HumanActivityMonitorManager_removeActivityRecognitionListener",
+                HumanActivityMonitorManagerRemoveActivityRecognitionListener);
 #undef REGISTER_SYNC
 }
 
@@ -218,6 +222,67 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerUnsetAccumulativeP
   // TODO(r.galka) implement
 }
 
+void HumanActivityMonitorInstance::HumanActivityMonitorManagerAddActivityRecognitionListener(
+    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;
+  }
+
+  const auto& listener_id = args.get("listenerId").get<std::string>();
+
+  JsonCallback cb = [this, listener_id](picojson::value* data) -> void {
+    if (!data) {
+      LOGGER(ERROR) << "No data passed to json callback";
+      return;
+    }
+
+    picojson::object& data_o = data->get<picojson::object>();
+    data_o["listenerId"] = picojson::value(listener_id);
+
+    Instance::PostMessage(this, data->serialize().c_str());
+  };
+
+  long watchId = 0;
+
+  result = manager_->AddActivityRecognitionListener(type, cb, args, &watchId);
+  if (result) {
+    out["watchId"] = picojson::value(static_cast<double>(watchId));
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out, ("Failed: manager_->AddActivityRecognitionListener()"));
+  }
+}
+
+void HumanActivityMonitorInstance::HumanActivityMonitorManagerRemoveActivityRecognitionListener(
+    const picojson::value& args, picojson::object& out) {
+  LoggerD("Enter");
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeHealthInfo, &out);
+  CHECK_EXIST(args, "watchId", out)
+
+  const long watchId = static_cast<long>(args.get("watchId").get<double>());
+
+  PlatformResult result = Init();
+  if (!result) {
+    LogAndReportError(result, &out, ("Failed: Init()"));
+    return;
+  }
+
+  result = manager_->RemoveActivityRecognitionListener(watchId);
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out, ("Failed: manager_->RemoveActivityRecognitionListener()"));
+  }
+}
+
 #undef CHECK_EXIST
 
 }  // namespace humanactivitymonitor
index cd0fa89..9ee22a7 100755 (executable)
@@ -42,6 +42,10 @@ class HumanActivityMonitorInstance : public common::ParsedInstance {
       const picojson::value& args, picojson::object& out);
   void HumanActivityMonitorManagerSetAccumulativePedometerListener(
       const picojson::value& args, picojson::object& out);
+  void HumanActivityMonitorManagerAddActivityRecognitionListener(
+      const picojson::value& args, picojson::object& out);
+  void HumanActivityMonitorManagerRemoveActivityRecognitionListener(
+      const picojson::value& args, picojson::object& out);
 
   std::shared_ptr<HumanActivityMonitorManager> manager_;
   common::PlatformResult Init();
index ab29a61..6ca88aa 100755 (executable)
 #include <gesture_recognition.h>
 
 #include "common/logger.h"
+#include "common/picojson.h"
+#include "common/tools.h"
 
 namespace extension {
 namespace humanactivitymonitor {
 
 using common::PlatformResult;
 using common::ErrorCode;
+using common::tools::ReportError;
+using common::tools::ReportSuccess;
+
+namespace {
+const std::string kActivityRecognitionStationary = "STATIONARY";
+const std::string kActivityRecognitionWalking = "WALKING";
+const std::string kActivityRecognitionRunning = "RUNNING";
+const std::string kActivityRecognitionInVehicle = "IN_VEHICLE";
+
+const std::string kActivityAccuracyLow = "LOW";
+const std::string kActivityAccuracyMedium = "MEDIUM";
+const std::string kActivityAccuracyHigh = "HIGH";
+
+long GetNextId() {
+  static long id = 0;
+  return ++id;
+}
+}
 
 HumanActivityMonitorManager::HumanActivityMonitorManager()
     : gesture_handle_(nullptr),
@@ -38,6 +58,12 @@ HumanActivityMonitorManager::~HumanActivityMonitorManager() {
   UnsetWristUpListener();
   UnsetHrmListener();
   UnsetGpsListener();
+
+  for (const auto& it: handles_cb_) {
+    activity_release(it.second->handle);
+    delete it.second;
+  }
+  handles_cb_.erase(handles_cb_.begin(), handles_cb_.end());
 }
 
 PlatformResult HumanActivityMonitorManager::Init() {
@@ -76,6 +102,42 @@ PlatformResult HumanActivityMonitorManager::IsSupported(
     }
   } else if (type == kActivityTypeGps) {
     supported = location_manager_is_supported_method(LOCATIONS_METHOD_GPS);
+  } else if (type == kActivityRecognitionStationary) {
+    ret = activity_is_supported(ACTIVITY_STATIONARY, &supported);
+    if (ret == ACTIVITY_ERROR_NOT_SUPPORTED || !supported) {
+      LoggerD("Type %s not supported", type.c_str());
+    } else if (ret != ACTIVITY_ERROR_NONE) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                                "activity_is_supported failed",
+                                ("activity_is_supported error %d - %s",ret, get_error_message(ret)));
+    }
+  } else if (type == kActivityRecognitionWalking) {
+    ret = activity_is_supported(ACTIVITY_WALK, &supported);
+    if (ret == ACTIVITY_ERROR_NOT_SUPPORTED || !supported) {
+      LoggerD("Type %s not supported", type.c_str());
+    } else if (ret != ACTIVITY_ERROR_NONE) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                                "activity_is_supported failed",
+                                ("activity_is_supported error %d - %s",ret, get_error_message(ret)));
+    }
+  } else if (type == kActivityRecognitionRunning) {
+    ret = activity_is_supported(ACTIVITY_RUN, &supported);
+    if (ret == ACTIVITY_ERROR_NOT_SUPPORTED || !supported) {
+      LoggerD("Type %s not supported", type.c_str());
+    } else if (ret != ACTIVITY_ERROR_NONE) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                                "activity_is_supported failed",
+                                ("activity_is_supported error %d - %s",ret, get_error_message(ret)));
+    }
+  } else if (type == kActivityRecognitionInVehicle) {
+    ret = activity_is_supported(ACTIVITY_IN_VEHICLE, &supported);
+    if (ret == ACTIVITY_ERROR_NOT_SUPPORTED || !supported) {
+      LoggerD("Type %s not supported", type.c_str());
+    } else if (ret != ACTIVITY_ERROR_NONE) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                                "activity_is_supported failed",
+                                ("activity_is_supported error %d - %s",ret, get_error_message(ret)));
+    }
   } else {
     return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR);
   }
@@ -141,6 +203,193 @@ PlatformResult HumanActivityMonitorManager::UnsetListener(
   return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Undefined activity type");
 }
 
+void HumanActivityMonitorManager:: ActivityRecognitionCb(
+                activity_type_e type,
+                const activity_data_h data,
+                double timestamp,
+                activity_error_e callback_error,
+                void *user_data) {
+  LoggerD("enter");
+
+  HandleCallback* handle_callback = static_cast<HandleCallback*>(user_data);
+  long watch_id = handle_callback->watch_id;
+  JsonCallback callback = handle_callback->callback;
+
+  picojson::value val = picojson::value(picojson::object());
+  picojson::object& obj = val.get<picojson::object>();
+  obj["watchId"] = picojson::value(static_cast<double>(watch_id));
+
+  if (callback_error != ACTIVITY_ERROR_NONE) {
+    LogAndReportError(
+        PlatformResult(ErrorCode::ABORT_ERR, "System operation was failed"),
+        &obj,
+        ("activity_recognition_cb() is failed with error code %d - %s", callback_error, get_error_message(callback_error)));
+    callback(&val);
+    return;
+  }
+
+  activity_accuracy_e accuracy = ACTIVITY_ACCURACY_MID;
+
+  int ret = activity_get_accuracy(data, &accuracy);
+  if (ret != ACTIVITY_ERROR_NONE) {
+    LogAndReportError(
+        PlatformResult(ErrorCode::ABORT_ERR, "System operation was failed"),
+        &obj,
+        ("activity_get_accuracy() is failed with error code %d - %s", ret, get_error_message(ret)));
+    callback(&val);
+    return;
+  }
+
+  const char *type_str;
+
+  switch (type) {
+    case ACTIVITY_STATIONARY:
+      type_str = kActivityRecognitionStationary.c_str();
+      break;
+
+    case ACTIVITY_WALK:
+      type_str = kActivityRecognitionWalking.c_str();
+      break;
+
+    case ACTIVITY_RUN:
+      type_str = kActivityRecognitionRunning.c_str();
+      break;
+
+    case ACTIVITY_IN_VEHICLE:
+      type_str = kActivityRecognitionInVehicle.c_str();
+      break;
+
+    default:
+      LogAndReportError(
+          PlatformResult(ErrorCode::ABORT_ERR, "Unknown activity recognition type"),
+          &obj,
+          ("Unknown activity recognition type %d", type));
+      callback(&val);
+      return;
+  }
+
+  LoggerD("Activity type: (%s)", type_str);
+
+  const char *accuracy_str;
+
+  switch (accuracy) {
+    case ACTIVITY_ACCURACY_LOW:
+      accuracy_str = kActivityAccuracyLow.c_str();
+      break;
+
+    case ACTIVITY_ACCURACY_MID:
+      accuracy_str = kActivityAccuracyMedium.c_str();
+      break;
+
+    case ACTIVITY_ACCURACY_HIGH:
+      accuracy_str = kActivityAccuracyHigh.c_str();
+      break;
+
+    default:
+      LogAndReportError(
+          PlatformResult(ErrorCode::ABORT_ERR, "Unknown activity accuracy type"),
+          &obj,
+          ("Unknown activity accuracy type %d", accuracy));
+      callback(&val);
+      return;
+  }
+
+  LoggerD("accuracy: (%s)", accuracy_str);
+  LoggerD("##### timeStamp: (%f)", timestamp);
+
+  picojson::value result = picojson::value(picojson::object());
+  picojson::object& result_obj = result.get<picojson::object>();
+
+  result_obj.insert(std::make_pair("type", picojson::value(type_str)));
+  result_obj.insert(std::make_pair("timestamp", picojson::value(timestamp)));
+  result_obj.insert(std::make_pair("accuracy", picojson::value(accuracy_str)));
+
+  ReportSuccess(result, obj);
+  callback(&val);
+  return;
+}
+
+PlatformResult HumanActivityMonitorManager:: AddActivityRecognitionListener(
+    const std::string& type, JsonCallback callback, const picojson::value& args, long* watch_id) {
+  LoggerD("Enter");
+
+  PlatformResult result = IsSupported(type);
+  if (!result) {
+    return result;
+  }
+
+  activity_type_e activity_type = ACTIVITY_STATIONARY;
+
+  if (type == kActivityRecognitionStationary) {
+    activity_type = ACTIVITY_STATIONARY;
+  } else if (type == kActivityRecognitionWalking) {
+    activity_type = ACTIVITY_WALK;
+  } else if (type == kActivityRecognitionRunning) {
+    activity_type = ACTIVITY_RUN;
+  } else if (type == kActivityRecognitionInVehicle) {
+    activity_type = ACTIVITY_IN_VEHICLE;
+  } else {
+    return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR,
+                              "A type not supported",
+                              ("The type %s is not matched with the activity recognition type", type.c_str()));
+  }
+
+  activity_h handle = nullptr;
+  int ret = activity_create(&handle);
+  if (ret != ACTIVITY_ERROR_NONE) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                              "activity_create error",
+                              ("activity_create error: %d - %s", ret, get_error_message(ret)));
+  }
+
+  long id = GetNextId();
+
+  // Adding the handle to handles map
+  HandleCallback* handle_callback = new HandleCallback(id, callback, handle);
+
+  handles_cb_[id] = handle_callback;
+
+  ret = activity_start_recognition(handle, activity_type, ActivityRecognitionCb, static_cast<void*>(handle_callback));
+  if (ret != ACTIVITY_ERROR_NONE) {
+    delete handle_callback;
+    handles_cb_.erase(id);
+    activity_release(handle);
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                              "activity_start_recognition error",
+                              ("activity_start_recognition error: %d - %s", ret, get_error_message(ret)));
+  }
+
+  *watch_id = id;
+
+  return result;
+}
+
+PlatformResult HumanActivityMonitorManager::RemoveActivityRecognitionListener(const long watch_id) {
+  LoggerD("Enter");
+
+  if (handles_cb_.find(watch_id) == handles_cb_.end()) {
+    return LogAndCreateResult(
+              ErrorCode::ABORT_ERR,
+              "Listener not found",
+              ("Listener with id = %ld not found", watch_id));
+  }
+  activity_h handle = handles_cb_[watch_id]->handle;
+
+  int ret = activity_stop_recognition(handle);
+  if (ret != ACTIVITY_ERROR_NONE) {
+    return LogAndCreateResult(
+              ErrorCode::ABORT_ERR,
+              "System operation was failed",
+              ("Activity_stop_recognition() return (%d) - %s", ret, get_error_message(ret)));
+  }
+
+  activity_release(handle);
+  delete handles_cb_[watch_id];
+  handles_cb_.erase(watch_id);
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 PlatformResult HumanActivityMonitorManager::GetHumanActivityData(
     const std::string& type,
     picojson::value* data) {
index 9d19468..b4943fe 100755 (executable)
@@ -20,6 +20,7 @@
 #include <functional>
 #include <sensor.h>
 #include <gesture_recognition.h>
+#include <activity_recognition.h>
 #include <location_batch.h>
 #include <string>
 
@@ -38,6 +39,13 @@ const std::string kActivityTypeGps = "GPS";
 
 typedef std::function<void(picojson::value*)> JsonCallback;
 
+typedef struct HandleCallbackStr {
+  HandleCallbackStr(long& id, JsonCallback& cb, activity_h& h) : watch_id(id), callback(cb), handle(h) {};
+  long watch_id;
+  JsonCallback callback;
+  activity_h handle;
+} HandleCallback;
+
 class HumanActivityMonitorManager {
  public:
   HumanActivityMonitorManager();
@@ -49,6 +57,10 @@ class HumanActivityMonitorManager {
       JsonCallback callback, const picojson::value& args);
   common::PlatformResult UnsetListener(const std::string& type);
 
+  common::PlatformResult AddActivityRecognitionListener(const std::string& type,
+      JsonCallback callback, const picojson::value& args, long* watchId);
+  common::PlatformResult RemoveActivityRecognitionListener(const long watchId);
+
   common::PlatformResult GetHumanActivityData(const std::string& type,
                                               picojson::value* data);
 
@@ -75,6 +87,7 @@ class HumanActivityMonitorManager {
   common::PlatformResult UnsetGpsListener();
   static void OnGpsEvent(int num_of_location, void *user_data);
   common::PlatformResult GetGpsData(picojson::value* data);
+  static void ActivityRecognitionCb(activity_type_e type, const activity_data_h data, double timestamp, activity_error_e callbackError, void *userData);
 
   // common
   std::map<std::string, bool> supported_;
@@ -87,6 +100,9 @@ class HumanActivityMonitorManager {
   // GPS
   location_manager_h location_handle_;
   JsonCallback gps_event_callback_;
+
+  // Activity recognition listeners handle map
+  std::map<long, HandleCallback*> handles_cb_;
 };
 
 } // namespace humanactivitymonitor