Merge "[Application] Fixed path of getAppSharedURI" into tizen_5.0
[platform/core/api/webapi-plugins.git] / src / humanactivitymonitor / humanactivitymonitor_api.js
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 var utils_ = xwalk.utils;
18 var privilege_ = utils_.privilege;
19 var type_ = utils_.type;
20 var converter_ = utils_.converter;
21 var validator_ = utils_.validator;
22 var types_ = validator_.Types;
23 var native_ = new xwalk.utils.NativeManager(extension);
24
25 var callbackId = 0;
26 var callbacks = {};
27
28 function nextCallbackId() {
29   return callbackId++;
30 }
31
32 function SetReadOnlyProperty(obj, n, v) {
33   Object.defineProperty(obj, n, {value: v, writable: false});
34 }
35
36 var ACCUMULATIVE_PEDOMETER_DATA = 'ACCUMULATIVE_PEDOMETER_DATA';
37 var MIN_OPTION_INTERVAL = 0;
38 var MIN_OPTION_RETENTION_PERIOD = 1;
39 var MIN_QUERY_TIME = 0;
40 var MIN_QUERY_INTERVAL = 0;
41
42 var HumanActivityType = {
43   PEDOMETER: 'PEDOMETER',
44   WRIST_UP: 'WRIST_UP',
45   HRM: 'HRM',
46   GPS: 'GPS',
47   SLEEP_MONITOR: 'SLEEP_MONITOR',
48   SLEEP_DETECTOR: 'SLEEP_DETECTOR',
49   STRESS_MONITOR: 'STRESS_MONITOR'
50 };
51
52 var HumanActivityRecorderType = {
53   PEDOMETER: 'PEDOMETER',
54   HRM: 'HRM',
55   SLEEP_MONITOR: 'SLEEP_MONITOR',
56   PRESSURE: 'PRESSURE'
57 };
58
59 var PedometerStepStatus = {
60   NOT_MOVING: 'NOT_MOVING',
61   WALKING: 'WALKING',
62   RUNNING: 'RUNNING',
63   UNKNOWN: 'UNKNOWN'
64 };
65
66 var ActivityRecognitionType = {
67   STATIONARY: 'STATIONARY',
68   WALKING: 'WALKING',
69   RUNNING: 'RUNNING',
70   IN_VEHICLE: 'IN_VEHICLE'
71 };
72
73 var ActivityAccuracy = {
74   LOW: 'LOW',
75   MEDIUM: 'MEDIUM',
76   HIGH: 'HIGH'
77 };
78
79 var SleepStatus = {
80   ASLEEP: 'ASLEEP',
81   AWAKE: 'AWAKE'
82 };
83
84 var GestureType = {
85   GESTURE_DOUBLE_TAP : 'GESTURE_DOUBLE_TAP',
86   GESTURE_MOVE_TO_EAR : 'GESTURE_MOVE_TO_EAR',
87   GESTURE_NO_MOVE : 'GESTURE_NO_MOVE',
88   GESTURE_PICK_UP : 'GESTURE_PICK_UP',
89   GESTURE_SHAKE : 'GESTURE_SHAKE',
90   GESTURE_SNAP : 'GESTURE_SNAP',
91   GESTURE_TILT : 'GESTURE_TILT',
92   GESTURE_TURN_FACE_DOWN : 'GESTURE_TURN_FACE_DOWN',
93   GESTURE_WRIST_UP : 'GESTURE_WRIST_UP',
94 };
95
96 function convertActivityData(type, data) {
97   switch (type) {
98     case HumanActivityType.PEDOMETER:
99       return new HumanActivityPedometerData(data);
100     case ACCUMULATIVE_PEDOMETER_DATA:
101       return new HumanActivityAccumulativePedometerData(data);
102     case HumanActivityType.WRIST_UP:
103       return null;
104     case HumanActivityType.HRM:
105       return new HumanActivityHRMData(data);
106     case HumanActivityType.GPS:
107       var gpsInfo = [];
108       for (var i = 0, max = data.gpsInfo.length; i < max; i++) {
109         gpsInfo.push(new HumanActivityGPSInfo(data.gpsInfo[i]));
110       }
111       return new HumanActivityGPSInfoArray(gpsInfo);
112     case HumanActivityType.SLEEP_MONITOR:
113       return new HumanActivitySleepMonitorData(data);
114     case HumanActivityType.SLEEP_DETECTOR:
115       return new HumanActivitySleepDetectorData(data);
116     case HumanActivityType.STRESS_MONITOR:
117       return new HumanActivityStressMonitorData(data);
118     default:
119       utils_.error('Uknown human activity type: ' + type);
120   }
121 }
122
123 function createRecorderData(func, data) {
124   var array = [];
125
126   data.forEach(function (d) {
127     array.push(new func(d));
128   });
129
130   return array;
131 }
132
133 function convertActivityRecorderData(type, data) {
134   var func = undefined;
135   switch (type) {
136     case HumanActivityRecorderType.PEDOMETER:
137       func = HumanActivityRecorderPedometerData;
138       break;
139     case HumanActivityRecorderType.HRM:
140       func = HumanActivityRecorderHRMData;
141       break;
142     case HumanActivityRecorderType.SLEEP_MONITOR:
143       func = HumanActivityRecorderSleepMonitorData;
144       break;
145     case HumanActivityRecorderType.PRESSURE:
146       func = HumanActivityRecorderPressureData;
147       break;
148     default:
149       utils_.error('Uknown human activity recorder type: ' + type);
150       return;
151   }
152
153   return createRecorderData(func, data);
154 }
155
156 function StressMonitorDataRange(label, min, max) {
157   validator_.validateConstructorCall(this, tizen.StressMonitorDataRange);
158
159   var args = validator_.validateArgs(arguments, [
160       { name: 'label', type: types_.STRING, optional: true, nullable: false },
161       { name: 'min', type: types_.UNSIGNED_LONG, optional: true, nullable: false },
162       { name: 'max', type: types_.UNSIGNED_LONG, optional: true, nullable: false }
163   ]);
164
165   var _label = !type_.isNullOrUndefined(args.label) ? args.label : "";
166   var _min = !type_.isNullOrUndefined(args.min) ? args.min : 0;
167   var _max = !type_.isNull(args.max) ? args.max : undefined;
168
169   Object.defineProperties(this, {
170     label: {
171       get: function() {
172         return _label;
173       },
174       set: function(v) {
175         _label = !type_.isNullOrUndefined(v) ? v : _label;
176       },
177       enumerable: true
178     },
179     min: {
180       get: function() {
181         return _min;
182       },
183       set: function(v) {
184         _min = !type_.isNullOrUndefined(v) ? converter_.toUnsignedLong(v) : _min;
185       },
186       enumerable: true
187     },
188     max: {
189       get: function() {
190         return _max;
191       },
192       set: function(v) {
193         _max = !type_.isNullOrUndefined(v) ? converter_.toUnsignedLong(v) : _max;
194       },
195       enumerable: true
196     }
197   });
198 };
199
200
201 function ActivityRecognitionListenerManager() {
202   this.listeners = {};
203   this.nextId = 1;
204   this.nativeSet = false;
205   this.native = native_;
206   this.listenerName = 'ActivityRecognitionListener';
207 };
208
209 ActivityRecognitionListenerManager.prototype.onListener = function(data) {
210   var watchId = data.watchId;
211
212   if (this.listeners[watchId]) {
213     if (native_.isFailure(data)) {
214       native_.callIfPossible(this.listeners[watchId].errorCallback, native_.getErrorObject(data));
215       return;
216     }
217
218     native_.callIfPossible(
219         this.listeners[watchId].listener,
220         new HumanActivityRecognitionData(native_.getResultObject(data)));
221   }
222 };
223
224 ActivityRecognitionListenerManager.prototype.addListener = function(watchId, listener, errorCallback) {
225   this.listeners[watchId] = {
226     listener: listener,
227     errorCallback: errorCallback
228   };
229
230   if (!this.nativeSet) {
231     this.native.addListener(this.listenerName, this.onListener.bind(this));
232     this.nativeSet = true;
233   }
234 };
235
236 ActivityRecognitionListenerManager.prototype.removeListener = function(watchId) {
237   if (this.listeners.hasOwnProperty(watchId)) {
238     delete this.listeners[watchId];
239     if (type_.isEmptyObject(this.listeners)) {
240       this.native.removeListener(this.listenerName);
241       this.nativeSet = false;
242     }
243   }
244 };
245
246 var activityRecognitionListener = new ActivityRecognitionListenerManager();
247
248 function HumanActivityMonitorManager() {
249 }
250
251 HumanActivityMonitorManager.prototype.getHumanActivityData = function(type, successCallback, errorCallback) {
252   var args = validator_.validateArgs(arguments, [
253     {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityType)},
254     {name: 'successCallback', type: types_.FUNCTION},
255     {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
256   ]);
257
258   if (-1 === [HumanActivityType.HRM, HumanActivityType.PEDOMETER].indexOf(args.type)) {
259     throw new WebAPIException(WebAPIException.NOT_SUPPORTED_ERR);
260   }
261
262   var data = {
263     type: args.type
264   };
265
266   var callback = function(result) {
267     if (native_.isFailure(result)) {
268       native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
269       return;
270     }
271
272     native_.callIfPossible(args.successCallback,
273         convertActivityData(args.type, native_.getResultObject(result)));
274   };
275
276   var result = native_.call('HumanActivityMonitorManager_getHumanActivityData', data, callback);
277
278   if (native_.isFailure(result)) {
279     throw native_.getErrorObject(result);
280   }
281 };
282
283 function startListener(listenerId, listener, method, data) {
284   if (!native_.isListenerSet(listenerId)) {
285     var result = native_.callSync(method, data);
286     if (native_.isFailure(result)) {
287       throw native_.getErrorObject(result);
288     }
289   }
290
291   // always set the listener, if it's another call to startListener() overwrite the old one
292   native_.addListener(listenerId, listener);
293 }
294
295 function checkPrivilegesForMethod(method, type) {
296   utils_.checkPrivilegeAccess(utils_.privilege.HEALTHINFO);
297   if ('HumanActivityMonitorManager_stop' === method && 'GPS' === type) {
298     utils_.checkPrivilegeAccess(utils_.privilege.LOCATION);
299   }
300 }
301
302 function stopListener(listenerId, method, data, doRemoval) {
303   if (!native_.isListenerSet(listenerId)) {
304     checkPrivilegesForMethod(method, data.type);
305     return;
306   }
307
308   if (doRemoval) {
309     var result = native_.callSync(method, data);
310     if (native_.isFailure(result)) {
311       throw native_.getErrorObject(result);
312     }
313
314     native_.removeListener(listenerId);
315   }
316 }
317
318 // Pedometer listener and accumulative pedometer listener are handled by a single
319 // callback. Native side sends both objects, JS side needs to pass the data to
320 // appropriate listeners.
321 var pedometerListener = null;
322 var accumulativePedometerListener = null;
323
324 function pedometerCallback(result) {
325   if (pedometerListener) {
326     pedometerListener(convertActivityData(HumanActivityType.PEDOMETER, result));
327   }
328
329   if (accumulativePedometerListener) {
330     accumulativePedometerListener(convertActivityData(ACCUMULATIVE_PEDOMETER_DATA, result));
331   }
332 }
333
334 var GPSListener = null;
335 function GPSCallback(result) {
336   if (GPSListener) {
337     GPSListener(result);
338   }
339 }
340
341 var stressListener = null;
342
343 HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
344   var args = validator_.validateArgs(arguments, [
345     {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityType)},
346     {name: 'changedCallback', type: types_.FUNCTION, optional: true, nullable: true},
347     {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true},
348     {name: 'options', type : types_.DICTIONARY, optional : true, nullable : true}
349   ]);
350
351   if (HumanActivityType.WRIST_UP === args.type) {
352     utils_.warn('DEPRECATION WARNING: HumanActivityType.WRIST_UP is deprecated since Tizen 4.0. '
353                      + 'Use GestureType and addGestureRecognitionListener to monitor WRIST_UP gesture');
354   }
355
356   var listenerId = 'HumanActivityMonitor_' + args.type;
357   var optionsAttributes = ["callbackInterval", "sampleInterval"], options = args.options || {};
358
359   var callbackInterval = null, sampleInterval = null;
360
361   switch (args.type) {
362   case HumanActivityType.GPS:
363     callbackInterval = !type_.isNullOrUndefined(options[optionsAttributes[0]]) ?
364         options[optionsAttributes[0]] : 150000;
365     sampleInterval = !type_.isNullOrUndefined(options[optionsAttributes[1]]) ?
366         options[optionsAttributes[1]] : 1000;
367     break;
368   case HumanActivityType.HRM:
369     callbackInterval = !type_.isNullOrUndefined(options[optionsAttributes[0]]) ?
370         options[optionsAttributes[0]] : 100;
371     if (callbackInterval < 10 || callbackInterval > 1000) {
372       throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR,
373                                 'callbackInterval is out of range');
374     }
375     break;
376   }
377
378   var listener = null;
379   switch (args.type) {
380     case HumanActivityType.PEDOMETER:
381       listener = pedometerCallback;
382       break;
383     case HumanActivityType.GPS:
384       listener = GPSCallback;
385       break;
386     case HumanActivityType.STRESS_MONITOR:
387       listener = stressMonitorListener.onListener;
388       break;
389     default:
390       listener = function(result) {
391         native_.callIfPossible(args.changedCallback, convertActivityData(args.type, result));
392       };
393   }
394
395   utils_.log("callbackInterval = " + callbackInterval + ", sampleInterval = " + sampleInterval);
396   startListener(listenerId,
397                 listener,
398                 'HumanActivityMonitorManager_start',
399                 { type: args.type,
400                   listenerId: listenerId,
401                   callbackInterval: callbackInterval,
402                   sampleInterval: sampleInterval
403                 }
404                );
405
406   if (HumanActivityType.PEDOMETER === args.type) {
407     pedometerListener = args.changedCallback;
408   }
409
410   if (HumanActivityType.GPS === args.type || HumanActivityType.STRESS_MONITOR === args.type) {
411     var callback = function(result) {
412       if (native_.isFailure(result)) {
413         native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
414       } else {
415         native_.callIfPossible(args.changedCallback, convertActivityData(args.type, result));
416       }
417     };
418
419     if (HumanActivityType.GPS === args.type) {
420       GPSListener = callback;
421     } else if (HumanActivityType.STRESS_MONITOR === args.type){
422       stressListener = callback;
423     }
424   }
425 };
426
427 HumanActivityMonitorManager.prototype.stop = function(type) {
428   var args = validator_.validateArgs(arguments, [
429     {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityType)}
430   ]);
431
432   if (HumanActivityType.WRIST_UP === args.type) {
433     utils_.warn('DEPRECATION WARNING: HumanActivityType.WRIST_UP is deprecated since Tizen 4.0. '
434                      + 'Use GestureType and addGestureRecognitionListener to monitor WRIST_UP gesture');
435   }
436
437   if (HumanActivityType.PEDOMETER === args.type) {
438     stopListener('HumanActivityMonitor_PEDOMETER',
439                  'HumanActivityMonitorManager_stop',
440                  { type: HumanActivityType.PEDOMETER },
441                  pedometerListener && !accumulativePedometerListener);
442     pedometerListener = null;
443   } else {
444     stopListener('HumanActivityMonitor_'  + args.type,
445                  'HumanActivityMonitorManager_stop',
446                  { type: args.type }, true);
447   }
448
449   if (HumanActivityType.GPS === args.type) {
450     GPSListener = null;
451   }
452
453   if (HumanActivityType.STRESS_MONITOR === args.type) {
454     stressListener = null;
455   }
456 };
457
458 HumanActivityMonitorManager.prototype.setAccumulativePedometerListener = function() {
459   var args = validator_.validateArgs(arguments, [
460     {name: 'changeCallback', type: types_.FUNCTION}
461   ]);
462
463   var oldPedometerListener = pedometerListener;
464
465   // calling start() will overwrite pedometerListener, needs to be restored afterwards
466   this.start(HumanActivityType.PEDOMETER, args.changeCallback);
467
468   accumulativePedometerListener = args.changeCallback;
469   pedometerListener = oldPedometerListener;
470 };
471
472 HumanActivityMonitorManager.prototype.unsetAccumulativePedometerListener = function() {
473   stopListener('HumanActivityMonitor_PEDOMETER',
474                'HumanActivityMonitorManager_stop',
475                { type: HumanActivityType.PEDOMETER },
476                accumulativePedometerListener && !pedometerListener);
477   accumulativePedometerListener = null;
478 };
479
480
481 HumanActivityMonitorManager.prototype.addActivityRecognitionListener = function() {
482   var args = validator_.validateArgs(arguments, [
483     {name: 'type', type: types_.ENUM, values: Object.keys(ActivityRecognitionType)},
484     {name: 'listener', type: types_.FUNCTION},
485     {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
486   ]);
487
488
489   var result = native_.call(
490                   'HumanActivityMonitorManager_addActivityRecognitionListener',
491                   { type: args.type,
492                     listenerId: activityRecognitionListener.listenerName });
493   if (native_.isFailure(result)) {
494     throw native_.getErrorObject(result);
495   }
496
497   var watchId = result.watchId;
498   activityRecognitionListener.addListener(watchId, args.listener, args.errorCallback);
499
500   return watchId;
501 };
502
503 HumanActivityMonitorManager.prototype.removeActivityRecognitionListener = function() {
504   var args = validator_.validateArgs(arguments, [
505     {name: 'watchId', type: types_.LONG},
506     {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
507   ]);
508
509   var result = native_.call(
510                   'HumanActivityMonitorManager_removeActivityRecognitionListener',
511                   { watchId: args.watchId });
512   if (native_.isFailure(result)) {
513     setTimeout(function () { native_.callIfPossible(args.errorCallback, native_.getErrorObject(result)); }, 0);
514     return;
515   }
516   activityRecognitionListener.removeListener(args.watchId);
517 };
518
519 HumanActivityMonitorManager.prototype.startRecorder = function() {
520   var args = validator_.validateArgs(arguments, [
521     {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)},
522     {name: 'options', type : types_.DICTIONARY, optional: true, nullable: false}
523   ]);
524
525   var callArgs = {};
526
527   if (args.options) {
528     if (MIN_OPTION_INTERVAL > args.options.interval ||
529         MIN_OPTION_RETENTION_PERIOD > args.options.interval) {
530       throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid option value');
531     }
532
533     callArgs.options = args.options;
534   }
535
536   callArgs.type = args.type;
537
538   var result = native_.callSync('HumanActivityMonitorManager_startRecorder', callArgs);
539
540   if (native_.isFailure(result)) {
541     throw native_.getErrorObject(result);
542   }
543 };
544
545 HumanActivityMonitorManager.prototype.stopRecorder = function() {
546   var args = validator_.validateArgs(arguments, [
547     {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)},
548   ]);
549
550   var callArgs = {};
551   callArgs.type = args.type;
552
553   var result = native_.callSync('HumanActivityMonitorManager_stopRecorder', callArgs);
554
555   if (native_.isFailure(result)) {
556     throw native_.getErrorObject(result);
557   }
558 };
559
560 HumanActivityMonitorManager.prototype.readRecorderData = function() {
561   var args = validator_.validateArgs(arguments, [
562     {name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityRecorderType)},
563     {name: 'query', type : types_.DICTIONARY, optional: false, nullable: true},
564     {name: 'successCallback', type: types_.FUNCTION},
565     {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
566   ]);
567
568   var callArgs = {};
569
570   if (args.query) {
571     if ((args.query.startTime && MIN_QUERY_TIME > args.query.startTime) ||
572         (args.query.endTime && MIN_QUERY_TIME > args.query.endTime) ||
573         (args.query.anchorTime && MIN_QUERY_TIME > args.query.anchorTime) ||
574         (args.query.interval && MIN_QUERY_INTERVAL > args.query.interval) ||
575         (args.query.startTime && args.query.endTime && args.query.startTime > args.query.endTime)) {
576       throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid query value');
577     }
578   }
579
580   callArgs.options = args.options;
581   callArgs.type = args.type;
582   callArgs.query = args.query;
583
584   var callback = function(result) {
585     if (native_.isFailure(result)) {
586         native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
587     } else {
588         var array = convertActivityRecorderData(args.type, native_.getResultObject(result));
589         args.successCallback(array);
590     }
591   };
592
593   var result = native_.call('HumanActivityMonitorManager_readRecorderData', callArgs, callback);
594
595   if (native_.isFailure(result)) {
596     throw native_.getErrorObject(result);
597   }
598 };
599
600 HumanActivityMonitorManager.prototype.isGestureSupported = function() {
601   var args = validator_.validateMethod(arguments, [{
602     name : 'type',
603     type: types_.ENUM,
604     values: Object.keys(GestureType)
605   }
606   ]);
607
608   var callArgs = {};
609   callArgs.type = args.type;
610
611   var result = native_.callSync('GestureManager_isGestureSupported', callArgs);
612   if (native_.isFailure(result)) {
613     throw native_.getErrorObject(result);
614   }
615
616   return native_.getResultObject(result);
617 };
618
619 function GestureListenerManager(native, listenerName) {
620   this.listeners = {};
621   //below maps keep information about number of registered listeners for the specific type
622   //there are two maps as one keeps information about listeners which should be always called
623   //and one keeps information about number of the listeners which should be called only
624   //if power-saving mode is off
625   this.typeCountMapDefault = {};
626   this.typeCountMapAlwaysOn = {};
627   this.nextId = 1;
628   this.nativeSet = false;
629   this.native = native;
630   this.listenerName = listenerName;
631   for (var type in GestureType) {
632     this.typeCountMapDefault[type] = this.typeCountMapAlwaysOn[type] = 0;
633   }
634 };
635
636 GestureListenerManager.prototype.onListenerCalled = function(msg) {
637   var d = undefined;
638   var result = undefined;
639   var alwaysOn = msg.alwaysOn;
640   switch (msg.action) {
641     case 'ondetect':
642       d = new GestureData(this.native.getResultObject(msg));
643       break;
644     case 'onerror':
645       d = this.native.getErrorObject(msg);
646       break;
647     default:
648       utils_.log('Unknown mode: ' + msg.action);
649       return;
650   }
651
652   for (var watchId in this.listeners) {
653     if (this.listeners.hasOwnProperty(watchId)) {
654       var listener = this.listeners[watchId];
655       var call = alwaysOn ? listener.alwaysOn : true;
656       if (call && listener[msg.action]) {
657         listener[msg.action](d);
658       }
659     }
660   }
661 };
662
663 GestureListenerManager.prototype.addListener = function(successCb, errorCb, type, alwaysOn) {
664   var listener = {
665       'type' : type,
666       'alwaysOn' : converter_.toBoolean(alwaysOn),
667       'ondetect' : successCb,
668       'onerror' : errorCb
669   };
670
671   var typeCountMap = alwaysOn ? this.typeCountMapAlwaysOn : this.typeCountMapDefault;
672   if (typeCountMap[type] === 0) {
673     var result = this.native.callSync('GestureManager_addGestureRecognitionListener', listener);
674     if (this.native.isFailure(result)) {
675       throw this.native.getErrorObject(result);
676     }
677   }
678
679   typeCountMap[type]++;
680   var id = this.nextId++;
681   this.listeners[id] = listener;
682
683   if (!this.nativeSet) {
684     this.native.addListener(this.listenerName, this.onListenerCalled.bind(this));
685     this.nativeSet = true;
686   }
687
688   return id;
689 };
690
691 GestureListenerManager.prototype.removeListener = function(watchId) {
692   if (this.listeners.hasOwnProperty(watchId)) {
693       var listener = this.listeners[watchId];
694       var typeCountMap = listener.alwaysOn ? this.typeCountMapAlwaysOn : this.typeCountMapDefault;
695
696       if (typeCountMap[listener.type] === 1) {
697         var result = this.native.callSync('GestureManager_removeGestureRecognitionListener', listener);
698         if (this.native.isFailure(result)) {
699           throw this.native.getErrorObject(result);
700         }
701       }
702
703       delete this.listeners[watchId];
704       typeCountMap[listener.type]--;
705   }
706
707   if (this.nativeSet && type_.isEmptyObject(this.listeners)) {
708     this.native.removeListener(this.listenerName);
709     this.nativeSet = false;
710   }
711 };
712
713 var GESTURE_RECOGNITION_LISTENER = 'GestureRecognitionListener';
714 var gestureRecognitionListener = new GestureListenerManager(native_, GESTURE_RECOGNITION_LISTENER);
715
716 HumanActivityMonitorManager.prototype.addGestureRecognitionListener = function() {
717   var args = validator_.validateMethod(arguments, [{
718     name : 'type',
719     type: types_.ENUM,
720     values: Object.keys(GestureType)
721   },
722   {
723     name : 'eventCallback',
724     type : types_.FUNCTION
725   },
726   {
727     name : 'errorCallback',
728     type : types_.FUNCTION,
729     optional: true,
730     nullable: true
731   },
732   {
733     name : 'alwaysOn',
734     type : types_.BOOLEAN,
735     optional : true,
736     nullable : true
737   }]);
738
739   return gestureRecognitionListener.addListener(args.eventCallback, args.errorCallback, args.type, args.alwaysOn);
740 };
741
742 HumanActivityMonitorManager.prototype.removeGestureRecognitionListener = function() {
743   var args = validator_.validateMethod(arguments, [{
744     name : 'watchId',
745     type : types_.LONG,
746   }]);
747
748   gestureRecognitionListener.removeListener(args.watchId);
749 };
750
751 function StressMonitorListenerManager() {
752   this.listeners = {};
753   this.nextId = 1;
754 };
755
756 StressMonitorListenerManager.prototype.onListener = function(data) {
757
758   if (stressListener) {
759     stressListener(data);
760   }
761   var score = data.stressScore;
762   for (var watchId in stressMonitorListener.listeners) {
763     if (stressMonitorListener.listeners.hasOwnProperty(watchId)) {
764       var _listener = stressMonitorListener.listeners[watchId];
765       var rangeArray = _listener.ranges;
766       for (var id in rangeArray) {
767         var _min = rangeArray[id].min;
768         var _max = !type_.isUndefined(rangeArray[id].max) ? rangeArray[id].max : Number.MAX_VALUE;
769         if ((score >= _min && score < _max) && (_listener.lastStressScore < _min || _listener.lastStressScore >= _max)) {
770           _listener.listener(rangeArray[id].label);
771         }
772       }
773       _listener.lastStressScore = score;
774     }
775   }
776 };
777
778 StressMonitorListenerManager.prototype.addListener = function(ranges, listener, errorCallback) {
779
780   var id = this.nextId++;
781
782   this.listeners[id] = {
783     ranges: ranges,
784     listener: listener,
785     lastStressScore: -1
786   };
787
788   return id;
789 };
790
791 StressMonitorListenerManager.prototype.removeListener = function(watchId) {
792   if (this.listeners.hasOwnProperty(watchId)) {
793     delete this.listeners[watchId];
794   }
795 };
796
797 var stressMonitorListener = new StressMonitorListenerManager();
798
799 HumanActivityMonitorManager.prototype.addStressMonitorChangeListener = function() {
800   utils_.checkPrivilegeAccess(privilege_.HEALTHINFO);
801   var args = validator_.validateMethod(arguments, [{
802     name : 'ranges',
803     type: types_.ARRAY,
804     values: StressMonitorDataRange
805   },
806   {
807     name : 'listener',
808     type : types_.FUNCTION
809   }]);
810
811   return stressMonitorListener.addListener(args.ranges, args.listener);
812 };
813
814 HumanActivityMonitorManager.prototype.removeStressMonitorChangeListener  = function() {
815   var args = validator_.validateMethod(arguments, [{
816     name : 'watchId',
817     type : types_.LONG,
818   }]);
819
820   stressMonitorListener.removeListener(args.watchId);
821 };
822
823 function StepDifference(data) {
824   SetReadOnlyProperty(this, 'stepCountDifference', data.stepCountDifference);
825   SetReadOnlyProperty(this, 'timestamp', data.timestamp);
826 }
827
828
829 function HumanActivityData() {
830 }
831
832
833 function HumanActivityPedometerData(data) {
834   SetReadOnlyProperty(this, 'stepStatus', data.stepStatus);
835   SetReadOnlyProperty(this, 'speed', data.speed);
836   SetReadOnlyProperty(this, 'walkingFrequency', data.walkingFrequency);
837   SetReadOnlyProperty(this, 'cumulativeDistance', data.cumulativeDistance);
838   SetReadOnlyProperty(this, 'cumulativeCalorie', data.cumulativeCalorie);
839   SetReadOnlyProperty(this, 'cumulativeTotalStepCount', data.cumulativeTotalStepCount);
840   SetReadOnlyProperty(this, 'cumulativeWalkStepCount', data.cumulativeWalkStepCount);
841   SetReadOnlyProperty(this, 'cumulativeRunStepCount', data.cumulativeRunStepCount);
842
843   var steps = [];
844   for (var i = 0; i < data.stepCountDifferences.length; ++i) {
845     steps.push(new StepDifference(data.stepCountDifferences[i]));
846   }
847   SetReadOnlyProperty(this, 'stepCountDifferences', steps);
848 }
849
850 HumanActivityPedometerData.prototype = new HumanActivityData();
851 HumanActivityPedometerData.prototype.constructor = HumanActivityPedometerData;
852
853
854 function HumanActivityAccumulativePedometerData(data) {
855   SetReadOnlyProperty(this, 'stepStatus', data.stepStatus);
856   SetReadOnlyProperty(this, 'speed', data.speed);
857   SetReadOnlyProperty(this, 'walkingFrequency', data.walkingFrequency);
858   SetReadOnlyProperty(this, 'accumulativeDistance', data.accumulativeDistance);
859   SetReadOnlyProperty(this, 'accumulativeCalorie', data.accumulativeCalorie);
860   SetReadOnlyProperty(this, 'accumulativeTotalStepCount', data.accumulativeTotalStepCount);
861   SetReadOnlyProperty(this, 'accumulativeWalkStepCount', data.accumulativeWalkStepCount);
862   SetReadOnlyProperty(this, 'accumulativeRunStepCount', data.accumulativeRunStepCount);
863
864   var steps = [];
865   for (var i = 0; i < data.stepCountDifferences.length; ++i) {
866     steps.push(new StepDifference(data.stepCountDifferences[i]));
867   }
868   SetReadOnlyProperty(this, 'stepCountDifferences', steps);
869 }
870
871 HumanActivityAccumulativePedometerData.prototype = new HumanActivityData();
872 HumanActivityAccumulativePedometerData.prototype.constructor = HumanActivityAccumulativePedometerData;
873
874
875 function HumanActivityHRMData(data) {
876   SetReadOnlyProperty(this, 'heartRate', data.heartRate);
877   SetReadOnlyProperty(this, 'rRInterval', data.rRInterval);
878 }
879
880 HumanActivityHRMData.prototype = new HumanActivityData();
881 HumanActivityHRMData.prototype.constructor = HumanActivityHRMData;
882
883 function HumanActivityRecognitionData(data) {
884   SetReadOnlyProperty(this, 'type', data.type);
885   SetReadOnlyProperty(this, 'timestamp', data.timestamp);
886   SetReadOnlyProperty(this, 'accuracy', data.accuracy);
887 }
888
889 HumanActivityRecognitionData.prototype = new HumanActivityData();
890 HumanActivityRecognitionData.prototype.constructor = HumanActivityRecognitionData;
891
892 function HumanActivityGPSInfo(data) {
893   SetReadOnlyProperty(this, 'latitude', data.latitude);
894   SetReadOnlyProperty(this, 'longitude', data.longitude);
895   SetReadOnlyProperty(this, 'altitude', data.altitude);
896   SetReadOnlyProperty(this, 'speed', data.speed);
897   SetReadOnlyProperty(this, 'errorRange', data.errorRange);
898   SetReadOnlyProperty(this, 'timestamp', data.timestamp);
899 }
900
901
902 function HumanActivityGPSInfoArray(data) {
903   SetReadOnlyProperty(this, 'gpsInfo', data);
904 }
905
906 HumanActivityGPSInfoArray.prototype = new HumanActivityData();
907 HumanActivityGPSInfoArray.prototype.constructor = HumanActivityGPSInfoArray;
908
909 function HumanActivitySleepMonitorData(data) {
910   SetReadOnlyProperty(this, 'status', data.status);
911   SetReadOnlyProperty(this, 'timestamp', data.timestamp);
912 }
913
914 HumanActivitySleepMonitorData.prototype = new HumanActivityData();
915 HumanActivitySleepMonitorData.prototype.constructor = HumanActivitySleepMonitorData;
916
917 function HumanActivitySleepDetectorData(data) {
918   SetReadOnlyProperty(this, 'status', data.status);
919 }
920
921 HumanActivitySleepDetectorData.prototype = new HumanActivityData();
922 HumanActivitySleepDetectorData.prototype.constructor = HumanActivitySleepMonitorData;
923
924 function HumanActivityStressMonitorData(data) {
925   SetReadOnlyProperty(this, 'stressScore', data.stressScore);
926 }
927
928 HumanActivityStressMonitorData.prototype = new HumanActivityData();
929 HumanActivityStressMonitorData.prototype.constructor = HumanActivityStressMonitorData
930
931 //Recorded data
932 function HumanActivityRecorderData(data) {
933   if (data) {
934     SetReadOnlyProperty(this, 'startTime', data.startTime);
935     SetReadOnlyProperty(this, 'endTime', data.endTime);
936   }
937 }
938
939 function HumanActivityRecorderPedometerData(data) {
940   HumanActivityRecorderData.call(this, data);
941   SetReadOnlyProperty(this, 'distance', data.distance);
942   SetReadOnlyProperty(this, 'calorie', data.calorie);
943   SetReadOnlyProperty(this, 'totalStepCount', data.totalStepCount);
944   SetReadOnlyProperty(this, 'walkStepCount', data.walkStepCount);
945   SetReadOnlyProperty(this, 'runStepCount', data.runStepCount);
946 }
947
948 HumanActivityRecorderPedometerData.prototype = new HumanActivityRecorderData();
949 HumanActivityRecorderPedometerData.prototype.constructor = HumanActivityRecorderPedometerData;
950
951 function HumanActivityRecorderHRMData(data) {
952   HumanActivityRecorderData.call(this, data);
953   SetReadOnlyProperty(this, 'heartRate', data.heartRate);
954 }
955
956 HumanActivityRecorderHRMData.prototype = new HumanActivityRecorderData();
957 HumanActivityRecorderHRMData.prototype.constructor = HumanActivityRecorderHRMData;
958
959 function HumanActivityRecorderSleepMonitorData(data) {
960   HumanActivityRecorderData.call(this, data);
961   SetReadOnlyProperty(this, 'status', data.status);
962 }
963
964 HumanActivityRecorderSleepMonitorData.prototype = new HumanActivityRecorderData();
965 HumanActivityRecorderSleepMonitorData.prototype.constructor = HumanActivityRecorderSleepMonitorData;
966
967 function HumanActivityRecorderPressureData(data) {
968   HumanActivityRecorderData.call(this, data);
969   SetReadOnlyProperty(this, 'max', data.max);
970   SetReadOnlyProperty(this, 'min', data.min);
971   SetReadOnlyProperty(this, 'average', data.average);
972 }
973
974 function GestureData(data) {
975   if (data) {
976     SetReadOnlyProperty(this, 'type', data.type);
977     SetReadOnlyProperty(this, 'event', data.event);
978     SetReadOnlyProperty(this, 'timestamp', data.timestamp);
979
980     if (data.type === 'GESTURE_TILT') {
981       SetReadOnlyProperty(this, 'x', data.x);
982       SetReadOnlyProperty(this, 'y', data.y);
983     } else {
984       SetReadOnlyProperty(this, 'x', null);
985       SetReadOnlyProperty(this, 'y', null);
986     }
987   }
988 }
989
990 HumanActivityRecorderPressureData.prototype = new HumanActivityRecorderData();
991 HumanActivityRecorderPressureData.prototype.constructor = HumanActivityRecorderPressureData;
992
993 tizen.StressMonitorDataRange = StressMonitorDataRange;
994
995 exports = new HumanActivityMonitorManager();