[HAM] Added pedometer support.
authorPawel Andruszkiewicz <p.andruszkie@samsung.com>
Tue, 5 Apr 2016 13:11:09 +0000 (15:11 +0200)
committerPawel Andruszkiewicz <p.andruszkie@samsung.com>
Wed, 6 Apr 2016 11:24:50 +0000 (13:24 +0200)
Change-Id: I9c454199a40ccd52a579e2a3ceb320a7d6a15fca
Signed-off-by: Pawel Andruszkiewicz <p.andruszkie@samsung.com>
packaging/webapi-plugins.spec
src/humanactivitymonitor/humanactivitymonitor.gyp
src/humanactivitymonitor/humanactivitymonitor_api.js
src/humanactivitymonitor/humanactivitymonitor_instance.cc
src/humanactivitymonitor/humanactivitymonitor_instance.h
src/humanactivitymonitor/humanactivitymonitor_manager.cc

index f339094344d771f74ed43ab6034d4b7858821c78..183a19b67efdabd84578224a3d151a00ac7ab1de 100644 (file)
@@ -338,6 +338,7 @@ BuildRequires: pkgconfig(capi-web-url-download)
 BuildRequires: pkgconfig(motion)
 BuildRequires: pkgconfig(capi-system-sensor)
 BuildRequires: pkgconfig(capi-location-manager)
+BuildRequires: pkgconfig(sensor)
 %endif
 
 %if 0%{?tizen_feature_iotcon_support}
index 38f27a38216c7e290a5c7b38bfb8e99a9d38628a..6c250c1871c3f03aa8c66afe3eb55aded36d336c 100755 (executable)
@@ -25,6 +25,7 @@
               'motion',
               'capi-system-sensor',
               'capi-location-manager',
+              'sensor',
             ]
           },
         }],
index b40a82a9b4f8ecf4f89e78125e6b2338f3f40c8c..e71b6a7b046aad991ca12de7fad7e905a82715aa 100755 (executable)
@@ -32,6 +32,8 @@ function SetReadOnlyProperty(obj, n, v) {
   Object.defineProperty(obj, n, {value: v, writable: false});
 }
 
+var ACCUMULATIVE_PEDOMETER_DATA = 'ACCUMULATIVE_PEDOMETER_DATA';
+
 var HumanActivityType = {
   PEDOMETER: 'PEDOMETER',
   WRIST_UP: 'WRIST_UP',
@@ -67,8 +69,9 @@ var SleepStatus = {
 function convertActivityData(type, data) {
   switch (type) {
     case HumanActivityType.PEDOMETER:
-      // TODO(r.galka) Not Supported in current implementation
-      return undefined;
+      return new HumanActivityPedometerData(data);
+    case ACCUMULATIVE_PEDOMETER_DATA:
+      return new HumanActivityAccumulativePedometerData(data);
     case HumanActivityType.WRIST_UP:
       return null;
     case HumanActivityType.HRM:
@@ -206,6 +209,22 @@ function stopListener(listenerId, method, data) {
   native_.removeListener(listenerId);
 }
 
+// Pedometer listener and accumulative pedometer listener are handled by a single
+// callback. Native side sends both objects, JS side needs to pass the data to
+// appropriate listeners.
+var pedometerListener = null;
+var accumulativePedometerListener = null;
+
+function pedometerCallback(result) {
+  if (pedometerListener) {
+    pedometerListener(convertActivityData(HumanActivityType.PEDOMETER, result));
+  }
+
+  if (accumulativePedometerListener) {
+    accumulativePedometerListener(convertActivityData(ACCUMULATIVE_PEDOMETER_DATA, result));
+  }
+}
+
 HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
   var args = validator_.validateArgs(arguments, [
     {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityType)},
@@ -241,11 +260,13 @@ HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
     break;
   }
 
+  var listener = HumanActivityType.PEDOMETER === args.type ? pedometerCallback : function(result) {
+    native_.callIfPossible(args.changedCallback, convertActivityData(args.type, result));
+  };
+
   console.log("callbackInterval = " + callbackInterval + ", sampleInterval = " + sampleInterval);
   startListener(listenerId,
-                function(result) {
-                  native_.callIfPossible(args.changedCallback, convertActivityData(args.type, result));
-                },
+                listener,
                 'HumanActivityMonitorManager_start',
                 { type: args.type,
                   listenerId: listenerId,
@@ -253,6 +274,10 @@ HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
                   sampleInterval: sampleInterval
                 }
                );
+
+  if (HumanActivityType.PEDOMETER === args.type) {
+    pedometerListener = args.changedCallback;
+  }
 };
 
 HumanActivityMonitorManager.prototype.stop = function(type) {
@@ -263,29 +288,34 @@ HumanActivityMonitorManager.prototype.stop = function(type) {
   stopListener('HumanActivityMonitor_'  + args.type,
                'HumanActivityMonitorManager_stop',
                { type: args.type });
-};
 
-var accumulativePedometerListenerId = 'HumanActivityMonitor_AccumulativePedometerListener';
+  if (HumanActivityType.PEDOMETER === args.type) {
+    pedometerListener = null;
+  }
+};
 
-HumanActivityMonitorManager.prototype.setAccumulativePedometerListener = function(changeCallback) {
+HumanActivityMonitorManager.prototype.setAccumulativePedometerListener = function() {
   var args = validator_.validateArgs(arguments, [
     {name: 'changeCallback', type: types_.FUNCTION}
   ]);
 
-  var listenerId = accumulativePedometerListenerId;
+  var oldPedometerListener = pedometerListener;
 
-  startListener(listenerId,
-                function(result) {
-                  args.changeCallback(convertActivityData(HumanActivityType.PEDOMETER, result));
-                },
-                'HumanActivityMonitorManager_setAccumulativePedometerListener',
-                { listenerId: listenerId });
+  // calling start() will overwrite pedometerListener, needs to be restored afterwards
+  this.start(HumanActivityType.PEDOMETER, args.changeCallback);
+
+  accumulativePedometerListener = args.changeCallback;
+  pedometerListener = oldPedometerListener;
 };
 
 HumanActivityMonitorManager.prototype.unsetAccumulativePedometerListener = function() {
-  stopListener(accumulativePedometerListenerId,
-               'HumanActivityMonitorManager_unsetAccumulativePedometerListener',
-               {});
+  var oldPedometerListener = pedometerListener;
+
+  // calling stop() will overwrite pedometerListener, needs to be restored afterwards
+  this.stop(HumanActivityType.PEDOMETER);
+
+  accumulativePedometerListener = null;
+  pedometerListener = oldPedometerListener;
 };
 
 
@@ -327,9 +357,9 @@ HumanActivityMonitorManager.prototype.removeActivityRecognitionListener = functi
   activityRecognitionListener.removeListener(args.watchId);
 };
 
-function StepDifference() {
-  SetReadOnlyProperty(this, 'stepCountDifference', null);
-  SetReadOnlyProperty(this, 'timestamp', null);
+function StepDifference(data) {
+  SetReadOnlyProperty(this, 'stepCountDifference', data.stepCountDifference);
+  SetReadOnlyProperty(this, 'timestamp', data.timestamp);
 }
 
 
@@ -337,32 +367,42 @@ function HumanActivityData() {
 }
 
 
-function HumanActivityPedometerData() {
-  SetReadOnlyProperty(this, 'stepStatus', null);
-  SetReadOnlyProperty(this, 'speed', null);
-  SetReadOnlyProperty(this, 'walkingFrequency', null);
-  SetReadOnlyProperty(this, 'cumulativeDistance', null);
-  SetReadOnlyProperty(this, 'cumulativeCalorie', null);
-  SetReadOnlyProperty(this, 'cumulativeTotalStepCount', null);
-  SetReadOnlyProperty(this, 'cumulativeWalkStepCount', null);
-  SetReadOnlyProperty(this, 'cumulativeRunStepCount', null);
-  SetReadOnlyProperty(this, 'stepCountDifferences', null);
+function HumanActivityPedometerData(data) {
+  SetReadOnlyProperty(this, 'stepStatus', data.stepStatus);
+  SetReadOnlyProperty(this, 'speed', data.speed);
+  SetReadOnlyProperty(this, 'walkingFrequency', data.walkingFrequency);
+  SetReadOnlyProperty(this, 'cumulativeDistance', data.cumulativeDistance);
+  SetReadOnlyProperty(this, 'cumulativeCalorie', data.cumulativeCalorie);
+  SetReadOnlyProperty(this, 'cumulativeTotalStepCount', data.cumulativeTotalStepCount);
+  SetReadOnlyProperty(this, 'cumulativeWalkStepCount', data.cumulativeWalkStepCount);
+  SetReadOnlyProperty(this, 'cumulativeRunStepCount', data.cumulativeRunStepCount);
+
+  var steps = [];
+  for (var i = 0; i < data.stepCountDifferences.length; ++i) {
+    steps.push(new StepDifference(data.stepCountDifferences[i]));
+  }
+  SetReadOnlyProperty(this, 'stepCountDifferences', steps);
 }
 
 HumanActivityPedometerData.prototype = new HumanActivityData();
 HumanActivityPedometerData.prototype.constructor = HumanActivityPedometerData;
 
 
-function HumanActivityAccumulativePedometerData() {
-  SetReadOnlyProperty(this, 'stepStatus', null);
-  SetReadOnlyProperty(this, 'speed', null);
-  SetReadOnlyProperty(this, 'walkingFrequency', null);
-  SetReadOnlyProperty(this, 'accumulativeDistance', null);
-  SetReadOnlyProperty(this, 'accumulativeCalorie', null);
-  SetReadOnlyProperty(this, 'accumulativeTotalStepCount', null);
-  SetReadOnlyProperty(this, 'accumulativeWalkStepCount', null);
-  SetReadOnlyProperty(this, 'accumulativeRunStepCount', null);
-  SetReadOnlyProperty(this, 'stepCountDifferences', null);
+function HumanActivityAccumulativePedometerData(data) {
+  SetReadOnlyProperty(this, 'stepStatus', data.stepStatus);
+  SetReadOnlyProperty(this, 'speed', data.speed);
+  SetReadOnlyProperty(this, 'walkingFrequency', data.walkingFrequency);
+  SetReadOnlyProperty(this, 'accumulativeDistance', data.accumulativeDistance);
+  SetReadOnlyProperty(this, 'accumulativeCalorie', data.accumulativeCalorie);
+  SetReadOnlyProperty(this, 'accumulativeTotalStepCount', data.accumulativeTotalStepCount);
+  SetReadOnlyProperty(this, 'accumulativeWalkStepCount', data.accumulativeWalkStepCount);
+  SetReadOnlyProperty(this, 'accumulativeRunStepCount', data.accumulativeRunStepCount);
+
+  var steps = [];
+  for (var i = 0; i < data.stepCountDifferences.length; ++i) {
+    steps.push(new StepDifference(data.stepCountDifferences[i]));
+  }
+  SetReadOnlyProperty(this, 'stepCountDifferences', steps);
 }
 
 HumanActivityAccumulativePedometerData.prototype = new HumanActivityData();
index f00a6b9bffe0c6b835b6bebf8b203900dc9680cc..d572ba34bcc7741a99099a3b54b35acf118217eb 100755 (executable)
@@ -54,10 +54,6 @@ HumanActivityMonitorInstance::HumanActivityMonitorInstance() {
                 HumanActivityMonitorManagerStart);
   REGISTER_SYNC("HumanActivityMonitorManager_stop",
                 HumanActivityMonitorManagerStop);
-  REGISTER_SYNC("HumanActivityMonitorManager_setAccumulativePedometerListener",
-                HumanActivityMonitorManagerSetAccumulativePedometerListener);
-  REGISTER_SYNC("HumanActivityMonitorManager_unsetAccumulativePedometerListener",
-                HumanActivityMonitorManagerUnsetAccumulativePedometerListener);
   REGISTER_SYNC("HumanActivityMonitorManager_addActivityRecognitionListener",
                 HumanActivityMonitorManagerAddActivityRecognitionListener);
   REGISTER_SYNC("HumanActivityMonitorManager_removeActivityRecognitionListener",
@@ -204,24 +200,6 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerStop(
   }
 }
 
-void HumanActivityMonitorInstance::HumanActivityMonitorManagerSetAccumulativePedometerListener(
-    const picojson::value& args, picojson::object& out) {
-  LoggerD("Enter");
-
-  CHECK_PRIVILEGE_ACCESS(kPrivilegeHealthInfo, &out);
-
-  // TODO(r.galka) implement
-}
-
-void HumanActivityMonitorInstance::HumanActivityMonitorManagerUnsetAccumulativePedometerListener(
-    const picojson::value& args, picojson::object& out) {
-  LoggerD("Enter");
-
-  CHECK_PRIVILEGE_ACCESS(kPrivilegeHealthInfo, &out);
-
-  // TODO(r.galka) implement
-}
-
 void HumanActivityMonitorInstance::HumanActivityMonitorManagerAddActivityRecognitionListener(
     const picojson::value& args, picojson::object& out) {
   LoggerD("Enter");
index 9ee22a78ba8cdc9ac4e48cc4ff931fe3ad79896b..07f0e1aefcfc5b7e736722035a976c587b7a4ef8 100755 (executable)
@@ -34,14 +34,10 @@ class HumanActivityMonitorInstance : public common::ParsedInstance {
  private:
   void HumanActivityMonitorManagerStop(
       const picojson::value& args, picojson::object& out);
-  void HumanActivityMonitorManagerUnsetAccumulativePedometerListener(
-      const picojson::value& args, picojson::object& out);
   void HumanActivityMonitorManagerGetHumanActivityData(
       const picojson::value& args, picojson::object& out);
   void HumanActivityMonitorManagerStart(
       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(
index a32dbf4828137f4fe503e6aa81037b80095bee27..d75da607a2c3fdaeb039225933c594beade61a05 100755 (executable)
@@ -20,6 +20,7 @@
 #include <gesture_recognition.h>
 #include <location_batch.h>
 #include <sensor.h>
+#include <sensor_internal.h>
 
 #include "common/logger.h"
 #include "common/optional.h"
@@ -51,6 +52,85 @@ const std::string kSampleInterval = "sampleInterval";
 const std::string kStatus = "status";
 const std::string kTimestamp = "timestamp";
 
+const std::string kStepStatus = "stepStatus";
+const std::string kSpeed = "speed";
+const std::string kWalkingFrequency = "walkingFrequency";
+const std::string kCumulativeDistance = "cumulativeDistance";
+const std::string kCumulativeCalorie = "cumulativeCalorie";
+const std::string kCumulativeTotalStepCount = "cumulativeTotalStepCount";
+const std::string kCumulativeWalkStepCount = "cumulativeWalkStepCount";
+const std::string kCumulativeRunStepCount = "cumulativeRunStepCount";
+const std::string kStepCountDifferences = "stepCountDifferences";
+const std::string kStepCountDifference = "stepCountDifference";
+
+const std::string kAccumulativeDistance = "accumulativeDistance";
+const std::string kAccumulativeCalorie = "accumulativeCalorie";
+const std::string kAccumulativeTotalStepCount = "accumulativeTotalStepCount";
+const std::string kAccumulativeWalkStepCount = "accumulativeWalkStepCount";
+const std::string kAccumulativeRunStepCount = "accumulativeRunStepCount";
+
+// helper structure, allows easier access to data values
+struct PedometerDataWrapper : public sensor_pedometer_data_t {
+  inline float steps() const {
+    return values[0];
+  }
+
+  inline float walk_steps() const {
+    return values[1];
+  }
+
+  inline float run_steps() const {
+    return values[2];
+  }
+
+  inline float distance() const {
+    return values[3];
+  }
+
+  inline float calories() const {
+    return values[4];
+  }
+
+  inline float speed() const {
+    return values[5];
+  }
+
+  inline float frequency() const {
+    return values[6];
+  }
+
+  inline sensor_pedometer_state_e state() const {
+    return static_cast<sensor_pedometer_state_e>(values[7]);
+  }
+};
+
+void InsertStepDifference(float step_difference, float timestamp, picojson::array* out) {
+  ScopeLogger();
+
+  picojson::object d;
+
+  d.insert(std::make_pair(kStepCountDifference, picojson::value(step_difference)));
+  d.insert(std::make_pair(kTimestamp, picojson::value(timestamp)));
+
+  out->push_back(picojson::value{d});
+}
+
+std::string FromSensorPedometerState(sensor_pedometer_state_e e) {
+  switch (e) {
+    case SENSOR_PEDOMETER_STATE_STOP:
+      return "NOT_MOVING";
+
+    case SENSOR_PEDOMETER_STATE_WALK:
+      return "WALKING";
+
+    case SENSOR_PEDOMETER_STATE_RUN:
+      return "RUNNING";
+
+    default:
+      return "UNKNOWN";
+  }
+}
+
 }  // namespace
 
 const std::string kActivityTypeGps = "GPS";
@@ -815,6 +895,51 @@ HumanActivityMonitorManager::HumanActivityMonitorManager()
     : activity_recognition_(std::make_shared<ActivityRecognition>()) {
   ScopeLogger();
 
+  auto convert_pedometer = [](sensor_event_s* event, picojson::object* data) -> PlatformResult {
+    ScopeLogger("convert_pedometer");
+
+    const auto pedometer_data = (PedometerDataWrapper*)event;
+
+    static const auto initial_pedometer_data = *pedometer_data;  // will be initialized only once
+    static float steps_so_far = 0.0;
+
+    const auto state = pedometer_data->state();
+
+    if (SENSOR_PEDOMETER_STATE_UNKNOWN == state) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown sensor step state");
+    }
+
+    data->insert(std::make_pair(kStepStatus, picojson::value(FromSensorPedometerState(state))));
+    data->insert(std::make_pair(kSpeed, picojson::value(pedometer_data->speed())));
+    data->insert(std::make_pair(kWalkingFrequency, picojson::value(pedometer_data->frequency())));
+
+    data->insert(std::make_pair(kCumulativeDistance, picojson::value(pedometer_data->distance() - initial_pedometer_data.distance())));
+    data->insert(std::make_pair(kCumulativeCalorie, picojson::value(pedometer_data->calories() - initial_pedometer_data.calories())));
+    data->insert(std::make_pair(kCumulativeTotalStepCount, picojson::value(pedometer_data->steps() - initial_pedometer_data.steps())));
+    data->insert(std::make_pair(kCumulativeWalkStepCount, picojson::value(pedometer_data->walk_steps() - initial_pedometer_data.walk_steps())));
+    data->insert(std::make_pair(kCumulativeRunStepCount, picojson::value(pedometer_data->run_steps() - initial_pedometer_data.run_steps())));
+
+    data->insert(std::make_pair(kAccumulativeDistance, picojson::value(pedometer_data->distance())));
+    data->insert(std::make_pair(kAccumulativeCalorie, picojson::value(pedometer_data->calories())));
+    data->insert(std::make_pair(kAccumulativeTotalStepCount, picojson::value(pedometer_data->steps())));
+    data->insert(std::make_pair(kAccumulativeWalkStepCount, picojson::value(pedometer_data->walk_steps())));
+    data->insert(std::make_pair(kAccumulativeRunStepCount, picojson::value(pedometer_data->run_steps())));
+
+    auto& diffs = data->insert(std::make_pair(kStepCountDifferences, picojson::value{picojson::array{}})).first->second.get<picojson::array>();
+
+    if (pedometer_data->diffs_count > 0) {
+      for (int i = 0; i < pedometer_data->diffs_count; ++i) {
+        InsertStepDifference(pedometer_data->diffs[i].steps, pedometer_data->diffs[i].timestamp, &diffs);
+      }
+    } else {
+      InsertStepDifference(steps_so_far > 0.0 ? pedometer_data->steps() - steps_so_far : 0.0, pedometer_data->timestamp, &diffs);
+    }
+
+    steps_so_far = pedometer_data->steps();
+
+    return PlatformResult(ErrorCode::NO_ERROR);
+  };
+
   auto convert_hrm = [](sensor_event_s* event, picojson::object* data) -> PlatformResult {
     ScopeLogger("convert_hrm");
 
@@ -879,7 +1004,7 @@ HumanActivityMonitorManager::HumanActivityMonitorManager()
     return PlatformResult(ErrorCode::NO_ERROR);
   };
 
-  monitors_.insert(std::make_pair(kActivityTypePedometer, std::make_shared<Monitor>(kActivityTypePedometer)));  // not supported
+  monitors_.insert(std::make_pair(kActivityTypePedometer, std::make_shared<Monitor::SensorMonitor>(kActivityTypePedometer, SENSOR_HUMAN_PEDOMETER, convert_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(kActivityTypeGps, std::make_shared<Monitor::GpsMonitor>(kActivityTypeGps)));