[Alarm]: Implementation of Tizen alarm API.
authoryejingfu <yejingfu@hotmail.com>
Wed, 11 Jun 2014 06:31:20 +0000 (14:31 +0800)
committeryejingfu <jingfu.ye@intel.com>
Fri, 20 Jun 2014 01:54:18 +0000 (09:54 +0800)
This commit implements the Alarm API:
  https://developer.tizen.org/dev-guide/2.2.0/org.tizen.web.device.apireference/tizen/alarm.html

There is a known issue about repeat alarm: if the working system time zone is set to Daylight saving time like PDT or EDT, the repeat alarm finds 3600 seconds gap on the initial trigger time.

BUG=XWALK-428

13 files changed:
alarm/alarm.gyp [new file with mode: 0644]
alarm/alarm_api.js [new file with mode: 0644]
alarm/alarm_extension.cc [new file with mode: 0644]
alarm/alarm_extension.h [new file with mode: 0644]
alarm/alarm_info.cc [new file with mode: 0644]
alarm/alarm_info.h [new file with mode: 0644]
alarm/alarm_instance.cc [new file with mode: 0644]
alarm/alarm_instance.h [new file with mode: 0644]
alarm/alarm_manager.cc [new file with mode: 0644]
alarm/alarm_manager.h [new file with mode: 0644]
examples/alarm.html [new file with mode: 0644]
examples/index.html
tizen-wrt.gyp

diff --git a/alarm/alarm.gyp b/alarm/alarm.gyp
new file mode 100644 (file)
index 0000000..1e98053
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  'includes':[
+    '../common/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'tizen_alarm',
+      'type': 'loadable_module',
+      'sources': [
+        'alarm_api.js',
+        'alarm_extension.cc',
+        'alarm_extension.h',
+        'alarm_info.cc',
+        'alarm_info.h',
+        'alarm_instance.cc',
+        'alarm_instance.h',
+        'alarm_manager.cc',
+        'alarm_manager.h',
+      ],
+      'conditions': [
+        ['tizen == 1', {
+          'includes': [
+            '../common/pkg-config.gypi',
+          ],
+          'variables': {
+            'packages': [
+              'appcore-common',
+              'capi-appfw-application',
+            ]
+          },
+        }],
+      ],
+    },
+  ],
+
+}
diff --git a/alarm/alarm_api.js b/alarm/alarm_api.js
new file mode 100644 (file)
index 0000000..c6d1053
--- /dev/null
@@ -0,0 +1,231 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function sendSyncMessage(msg) {
+  return JSON.parse(extension.internal.sendSyncMessage(JSON.stringify(msg)));
+}
+
+function daysOfWeekToFlag(days) {
+  var flag = 0;
+  if (days instanceof Array && days.length > 0) {
+    for (var i = 0, len = days.length; i < len; i++) {
+      var day = days[i];
+      if (day === 'SU')
+        flag |= 0x01;
+      else if (day === 'MO')
+        flag |= 0x02;
+      else if (day === 'TU')
+        flag |= 0x04;
+      else if (day === 'WE')
+        flag |= 0x08;
+      else if (day === 'TH')
+        flag |= 0x10;
+      else if (day === 'FR')
+        flag |= 0x20;
+      else if (day === 'SA')
+        flag |= 0x40;
+    }
+  }
+
+  return flag;
+}
+
+function flagToDaysOfWeek(flag) {
+  var days = [];
+  if (flag & 0x01)
+    days.push('SU');
+  if (flag & 0x02)
+    days.push('MO');
+  if (flag & 0x04)
+    days.push('TU');
+  if (flag & 0x08)
+    days.push('WE');
+  if (flag & 0x10)
+    days.push('TH');
+  if (flag & 0x20)
+    days.push('FR');
+  if (flag & 0x40)
+    days.push('SA');
+
+  return days;
+}
+
+function defineReadOnlyProperty(object, key, value) {
+  Object.defineProperty(object, key, {
+    enumerable: true,
+    writable: false,
+    value: value
+  });
+}
+
+var OperationEnum = {
+  AddAlarmAbs: 'alarm.add.absolute',
+  AddAlarmRel: 'alarm.add.relative',
+  GetRemainingSec: 'alarm.get.remainingsec',
+  GetNextScheduledDate: 'alarm.get.nextScheduledDate',
+  RemoveAlarm: 'alarm.remove',
+  RemoveAllAlarm: 'alarm.removeAll',
+  GetAlarm: 'alarm.getInfo',
+  GetAllAlarms: 'alarm.getAllInfo'
+};
+
+defineReadOnlyProperty(exports, 'PERIOD_MINUTE', 60);
+defineReadOnlyProperty(exports, 'PERIOD_HOUR', 3600);
+defineReadOnlyProperty(exports, 'PERIOD_DAY', 86400);
+defineReadOnlyProperty(exports, 'PERIOD_WEEK', 604800);
+
+tizen.Alarm = function() {};
+tizen.Alarm.prototype.constructor = tizen.Alarm;
+
+tizen.AlarmAbsolute = function(date, periodOrDaysOfWeek) {
+  tizen.Alarm.apply(this);
+
+  if (date instanceof Date) {
+    defineReadOnlyProperty(this, 'date', date);
+  } else {
+    throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+  }
+
+  var daysOfTheWeek = [];
+  if (typeof periodOrDaysOfWeek === 'number' && !isNaN(periodOrDaysOfWeek)) {
+    defineReadOnlyProperty(this, 'period', periodOrDaysOfWeek);
+  } else if (periodOrDaysOfWeek instanceof Array && periodOrDaysOfWeek.length > 0) {
+    daysOfTheWeek = periodOrDaysOfWeek;
+  }
+  defineReadOnlyProperty(this, 'daysOfTheWeek', daysOfTheWeek);
+};
+
+tizen.AlarmAbsolute.prototype = new tizen.Alarm();
+tizen.AlarmAbsolute.prototype.constructor = tizen.AlarmAbsolute;
+
+tizen.AlarmAbsolute.prototype.getNextScheduledDate = function() {
+  if (this.id === undefined) {
+    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
+  }
+
+  var operation = { cmd: OperationEnum.GetNextScheduledDate, alarm: this.id };
+  var ret = sendSyncMessage(operation);
+  if (ret.error) {
+    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
+  }
+
+  var seconds = ret.data['nextScheduledDate'] || 0;
+  return new Date(seconds * 1000);
+};
+
+tizen.AlarmRelative = function(delay, period) {
+  tizen.Alarm.apply(this);
+
+  if (typeof delay === 'number' && !isNaN(delay))
+    defineReadOnlyProperty(this, 'delay', delay);
+  else
+    throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+
+  if (typeof period === 'number' && !isNaN(period))
+    defineReadOnlyProperty(this, 'period', period);
+};
+
+tizen.AlarmRelative.prototype = new tizen.Alarm();
+tizen.AlarmRelative.prototype.constructor = tizen.AlarmRelative;
+
+tizen.AlarmRelative.prototype.getRemainingSeconds = function() {
+  if (this.id === undefined)
+    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
+
+  var operation = { cmd: OperationEnum.GetRemainingSec, alarm: this.id };
+  var ret = sendSyncMessage(operation);
+  if (ret.error)
+    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
+
+  return ret.data['remainingSeconds'];
+};
+
+exports.add = function(alarm, applicationId, appControl) {
+  var cmd = undefined;
+  var alarmInfo = {};
+  if (alarm instanceof tizen.AlarmAbsolute) {
+    cmd = OperationEnum.AddAlarmAbs;
+    // Convert milliseconds to seconds and round it.
+    alarmInfo['date'] = Math.floor(alarm.date.getTime() / 1000 + 0.5);
+    alarmInfo['period'] = alarm.period || 0;
+    alarmInfo['daysOfTheWeek'] = daysOfWeekToFlag(alarm.daysOfTheWeek);
+  } else if (alarm instanceof tizen.AlarmRelative) {
+    cmd = OperationEnum.AddAlarmRel;
+    alarmInfo['delay'] = alarm.delay;
+    alarmInfo['period'] = alarm.period || 0;
+  } else {
+    throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+  }
+
+  var operation = {
+    cmd: cmd,
+    alarm: alarmInfo,
+    applicationId: applicationId,
+    appControl: appControl
+  };
+  var ret = sendSyncMessage(operation);
+  if (ret.error)
+    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
+
+  defineReadOnlyProperty(alarm, 'id', ret.data['id']);
+};
+
+exports.remove = function(alarmId) {
+  var operation = { cmd: OperationEnum.RemoveAlarm, alarm: alarmId };
+  var ret = sendSyncMessage(operation);
+  if (ret.error)
+    throw new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR);
+  console.debug('Succeed to remove alarm ' + alarmId);
+};
+
+exports.removeAll = function() {
+  var operation = { cmd: OperationEnum.RemoveAllAlarm };
+  var ret = sendSyncMessage(operation);
+  if (ret.error)
+    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
+  console.debug('Succeed to remove all alarms');
+};
+
+function parseAlarm(data) {
+  var alarm = null;
+  var obj = JSON.parse(data);
+
+  if (obj['type'] === 'absolute') {
+    // Convert seconds to milliseconds and use it to create Date object.
+    var date = new Date(obj['date'] * 1000);
+    var daysOfTheWeek = flagToDaysOfWeek(obj['weekFlag']);
+    alarm = new tizen.AlarmAbsolute(date, daysOfTheWeek.length > 0 ? daysOfTheWeek : obj['period']);
+    defineReadOnlyProperty(alarm, 'id', obj['id']);
+  } else if (obj['type'] === 'relative') {
+    alarm = new tizen.AlarmRelative(obj['delay'], obj['period']);
+    defineReadOnlyProperty(alarm, 'id', obj['id']);
+  }
+
+  return alarm;
+}
+
+exports.get = function(alarmId) {
+  var operation = { cmd: OperationEnum.GetAlarm, alarm: alarmId };
+  var ret = sendSyncMessage(operation);
+  if (ret.error)
+    throw new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR);
+  else if (!ret.data)
+    throw new tizen.WebAPIException(tizen.WebAPIException.INVALID_VALUES_ERR);
+
+  return parseAlarm(ret.data);
+};
+
+exports.getAll = function() {
+  var operation = { cmd: OperationEnum.GetAllAlarms };
+  var ret = sendSyncMessage(operation);
+  if (ret.error || !ret.data)
+    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
+
+  var alarms = [];
+  for (var i = 0, len = ret.data.length; i < len; i++) {
+    var alarm = parseAlarm(ret.data[i]);
+    alarms.push(alarm);
+  }
+  return alarms;
+};
diff --git a/alarm/alarm_extension.cc b/alarm/alarm_extension.cc
new file mode 100644 (file)
index 0000000..1602207
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "alarm/alarm_extension.h"
+
+#include "alarm/alarm_instance.h"
+
+common::Extension* CreateExtension() {
+  return new AlarmExtension;
+}
+
+// This will be generated from alarm_api.js.
+extern const char kSource_alarm_api[];
+
+AlarmExtension::AlarmExtension() {
+  SetExtensionName("tizen.alarm");
+  SetJavaScriptAPI(kSource_alarm_api);
+  const char* entry_points[] = {
+    "tizen.AlarmAbsolute",
+    "tizen.AlarmRelative",
+    NULL
+  };
+  SetExtraJSEntryPoints(entry_points);
+}
+
+AlarmExtension::~AlarmExtension() {}
+
+common::Instance* AlarmExtension::CreateInstance() {
+  return new AlarmInstance();
+}
diff --git a/alarm/alarm_extension.h b/alarm/alarm_extension.h
new file mode 100644 (file)
index 0000000..14326f7
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ALARM_ALARM_EXTENSION_H_
+#define ALARM_ALARM_EXTENSION_H_
+
+#include "common/extension.h"
+
+class AlarmExtension : public common::Extension {
+ public:
+  AlarmExtension();
+  virtual ~AlarmExtension();
+
+ private:
+  virtual common::Instance* CreateInstance();
+};
+
+#endif  // ALARM_ALARM_EXTENSION_H_
diff --git a/alarm/alarm_info.cc b/alarm/alarm_info.cc
new file mode 100644 (file)
index 0000000..2c2ed69
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "alarm/alarm_info.h"
+
+#include <iostream>
+
+#include "common/picojson.h"
+
+std::string AlarmInfo::Serialize() {
+  picojson::object obj;
+  obj["id"] = picojson::value(static_cast<double>(id_));
+
+  if (type_ == ABSOLUTE) {
+    obj["type"] = picojson::value(std::string("absolute"));
+    obj["date"] = picojson::value(static_cast<double>(date_));
+    obj["period"] = picojson::value(static_cast<double>(period_));
+    obj["weekFlag"] = picojson::value(static_cast<double>(weekflag_));
+  } else if (type_ == RELATIVE) {
+    obj["type"] = picojson::value(std::string("relative"));
+    obj["delay"] = picojson::value(static_cast<double>(delay_));
+    obj["period"] = picojson::value(static_cast<double>(period_));
+  } else {
+    // Should never come here.
+    std::cerr << "Unknown alarm type " << type_ << std::endl;
+  }
+
+  picojson::value val(obj);
+  return val.serialize();
+}
+
+bool AlarmInfo::Deserialize(const char* stream) {
+  picojson::value obj;
+
+  std::string err;
+  picojson::parse(obj, stream, stream + strlen(stream), &err);
+  if (!err.empty()) {
+    std::cerr << "Failed to deserialize alarm object: " << stream << std::endl;
+    return false;
+  }
+
+  id_ = static_cast<int>(obj.get("id").get<double>());
+  std::string type = obj.get("type").to_str();
+
+  if (type == "absolute") {
+    type_ = ABSOLUTE;
+    date_ = static_cast<int>(obj.get("date").get<double>());
+    period_ = static_cast<int>(obj.get("period").get<double>());
+    weekflag_ = static_cast<int>(obj.get("weekFlag").get<double>());
+  } else if (type == "relative") {
+    type_ = RELATIVE;
+    delay_ = static_cast<int>(obj.get("delay").get<double>());
+    period_ = static_cast<int>(obj.get("period").get<double>());
+  } else {
+    std::cerr << "Unknown alarm type " << type << std::endl;
+    return false;
+  }
+
+  return true;
+}
diff --git a/alarm/alarm_info.h b/alarm/alarm_info.h
new file mode 100644 (file)
index 0000000..128ac87
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ALARM_ALARM_INFO_H_
+#define ALARM_ALARM_INFO_H_
+
+#include <string>
+
+class AlarmInfo {
+ public:
+  enum AlarmType {
+    ABSOLUTE,
+    RELATIVE
+  };
+
+  AlarmInfo() {}
+  AlarmInfo(int id, AlarmType type, int date,
+            int delay, int period, int weekflag)
+    : id_(id), type_(type), date_(date), delay_(delay),
+      period_(period), weekflag_(weekflag) {}
+
+  ~AlarmInfo() {}
+
+  int id() const { return id_; }
+  void SetId(int id) { id_ = id; }
+  int type() const { return type_; }
+  int date() const { return date_; }
+  int delay() const { return delay_; }
+  int period() const { return period_; }
+  int weekflag() const { return weekflag_; }
+
+  std::string Serialize();
+  bool Deserialize(const char* stream);
+
+ private:
+  int id_;
+  AlarmType type_;
+  int date_;
+  int delay_;
+  int period_;
+  int weekflag_;
+};
+
+#endif  // ALARM_ALARM_INFO_H_
diff --git a/alarm/alarm_instance.cc b/alarm/alarm_instance.cc
new file mode 100644 (file)
index 0000000..adee5fa
--- /dev/null
@@ -0,0 +1,196 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "alarm/alarm_instance.h"
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "alarm/alarm_info.h"
+#include "alarm/alarm_manager.h"
+
+namespace {
+
+const char cmdAddAbsAlarm[] = "alarm.add.absolute";
+const char cmdAddRelAlarm[] = "alarm.add.relative";
+const char cmdGetRemainingSec[] = "alarm.get.remainingsec";
+const char cmdGetNextScheduledDate[] = "alarm.get.nextScheduledDate";
+const char cmdGetAlarm[] = "alarm.getInfo";
+const char cmdGetAllAlarms[] = "alarm.getAllInfo";
+const char cmdRemoveAlarm[] = "alarm.remove";
+const char cmdRemoveAllAlarm[] = "alarm.removeAll";
+
+}  // namespace
+
+AlarmInstance::AlarmInstance() {
+  alarm_manager_.reset(new AlarmManager());
+
+  // Store the host application Id into the manager.
+  std::string id_str = common::Extension::GetRuntimeVariable("app_id", 64);
+  std::istringstream buf(id_str);
+  picojson::value id_val;
+  picojson::parse(id_val, buf);
+  alarm_manager_->SetHostAppId(id_val.get<std::string>());
+}
+
+AlarmInstance::~AlarmInstance() {}
+
+void AlarmInstance::HandleMessage(const char* msg) {
+  picojson::value msg_obj;
+  std::string err;
+  picojson::parse(msg_obj, msg, msg + strlen(msg), &err);
+  if (!err.empty()) {
+    std::cerr << "Failed to parse the message." << std::endl;
+    return;
+  }
+}
+
+void AlarmInstance::HandleSyncMessage(const char* msg) {
+  picojson::value msg_obj;
+  std::string err;
+  picojson::parse(msg_obj, msg, msg + strlen(msg), &err);
+  if (!err.empty()) {
+    std::cerr << "Failed to parse the sync message: " << msg << std::endl;
+    return;
+  }
+
+  std::string cmdName = msg_obj.get("cmd").to_str();
+  if (cmdName == cmdAddAbsAlarm)
+    HandleAddAbsoluteAlarm(msg_obj);
+  else if (cmdName == cmdAddRelAlarm)
+    HandleAddRelativeAlarm(msg_obj);
+  else if (cmdName == cmdGetRemainingSec)
+    HandleGetRemainingSeconds(msg_obj);
+  else if (cmdName == cmdGetNextScheduledDate)
+    HandleGetNextScheduledDate(msg_obj);
+  else if (cmdName == cmdGetAlarm)
+    HandleGetAlarm(msg_obj);
+  else if (cmdName == cmdGetAllAlarms)
+    HandleGetAllAlarms();
+  else if (cmdName == cmdRemoveAlarm)
+    HandleRemoveAlarm(msg_obj);
+  else if (cmdName == cmdRemoveAllAlarm)
+    HandleRemoveAllAlarms();
+}
+
+void AlarmInstance::HandleAddAbsoluteAlarm(const picojson::value& msg) {
+  std::string app_id = msg.get("applicationId").to_str();
+  picojson::value alarm_value = msg.get("alarm");
+  int dateval = static_cast<int>(alarm_value.get("date").get<double>());
+  int period = static_cast<int>(alarm_value.get("period").get<double>());
+  int week_flag = static_cast<int>(alarm_value.get("daysOfTheWeek")
+      .get<double>());
+
+  std::unique_ptr<AlarmInfo> alarm(new AlarmInfo(0, AlarmInfo::ABSOLUTE,
+      dateval, 0, period, week_flag));
+
+  int ret = alarm_manager_->ScheduleAlarm(app_id, alarm.get());
+
+  if (!ret) {
+    picojson::object obj;
+    obj["id"] = picojson::value(static_cast<double>(alarm->id()));
+    SendSyncMessage(0, picojson::value(obj));
+  } else {
+    SendSyncMessage(ret,
+        picojson::value(std::string("Failed to add alarm")));
+  }
+}
+
+void AlarmInstance::HandleAddRelativeAlarm(const picojson::value& msg) {
+  std::string app_id = msg.get("applicationId").to_str();
+  picojson::value alarm_value = msg.get("alarm");
+  int delay = static_cast<int>(alarm_value.get("delay").get<double>());
+  int period = static_cast<int>(alarm_value.get("period").get<double>());
+
+  std::unique_ptr<AlarmInfo> alarm(new AlarmInfo(0, AlarmInfo::RELATIVE,
+      0, delay, period, 0));
+
+  int ret = alarm_manager_->ScheduleAlarm(app_id, alarm.get());
+
+  if (!ret) {
+    picojson::object obj;
+    obj["id"] = picojson::value(static_cast<double>(alarm->id()));
+    SendSyncMessage(0, picojson::value(obj));
+  } else {
+    SendSyncMessage(ret,
+        picojson::value(std::string("Failed to add alarm")));
+  }
+}
+
+void AlarmInstance::HandleGetRemainingSeconds(const picojson::value& msg) {
+  int alarm_id = static_cast<int>(msg.get("alarm").get<double>());
+  int seconds = 0;
+
+  int ret = alarm_manager_->GetRemainingSeconds(alarm_id, seconds);
+
+  if (!ret) {
+    picojson::object obj;
+    obj["remainingSeconds"] = picojson::value(static_cast<double>(seconds));
+    SendSyncMessage(ret, picojson::value(obj));
+  } else {
+    SendSyncMessage(ret, picojson::value(std::string("")));
+  }
+}
+
+void AlarmInstance::HandleGetNextScheduledDate(const picojson::value& msg) {
+  int alarm_id = static_cast<int>(msg.get("alarm").get<double>());
+  int date = 0;
+
+  int ret = alarm_manager_->GetNextScheduledDate(alarm_id, date);
+
+  if (!ret) {
+    picojson::object obj;
+    obj["nextScheduledDate"] = picojson::value(static_cast<double>(date));
+    SendSyncMessage(ret, picojson::value(obj));
+  } else {
+    SendSyncMessage(ret, picojson::value(std::string("")));
+  }
+}
+
+void AlarmInstance::HandleGetAlarm(const picojson::value& msg) {
+  int alarm_id = static_cast<int>(msg.get("alarm").get<double>());
+  std::unique_ptr<AlarmInfo> alarm(new AlarmInfo());
+
+  int ret = alarm_manager_->GetAlarm(alarm_id, alarm.get());
+
+  if (!ret) {
+    SendSyncMessage(0, picojson::value(alarm->Serialize()));
+  } else {
+    SendSyncMessage(ret, picojson::value(std::string("Not found.")));
+  }
+}
+
+void AlarmInstance::HandleGetAllAlarms() {
+  std::vector<std::shared_ptr<AlarmInfo> > alarms;
+
+  int ret = alarm_manager_->GetAllAlarms(alarms);
+  picojson::array alarm_infos;
+  for (int i = 0; i < alarms.size(); i++) {
+    alarm_infos.push_back(picojson::value(alarms[i]->Serialize()));
+  }
+
+  SendSyncMessage(0, picojson::value(alarm_infos));
+}
+
+void AlarmInstance::HandleRemoveAlarm(const picojson::value& msg) {
+  int alarm_id = static_cast<int>(msg.get("alarm").get<double>());
+  int ret = alarm_manager_->RemoveAlarm(alarm_id);
+  SendSyncMessage(ret, picojson::value(std::string("")));
+}
+
+void AlarmInstance::HandleRemoveAllAlarms() {
+  int ret = alarm_manager_->RemoveAllAlarms();
+  SendSyncMessage(ret, picojson::value(std::string("")));
+}
+
+void AlarmInstance::SendSyncMessage(int err_code, const picojson::value& data) {
+  picojson::object obj;
+  if (err_code)
+    obj["error"] = picojson::value(static_cast<double>(err_code));
+  obj["data"] = data;
+  picojson::value val(obj);
+  SendSyncReply(val.serialize().c_str());
+}
diff --git a/alarm/alarm_instance.h b/alarm/alarm_instance.h
new file mode 100644 (file)
index 0000000..a9cc42d
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ALARM_ALARM_INSTANCE_H_
+#define ALARM_ALARM_INSTANCE_H_
+
+#include <memory>
+
+#include "common/extension.h"
+#include "common/picojson.h"
+
+class AlarmManager;
+
+class AlarmInstance : public common::Instance {
+ public:
+  AlarmInstance();
+  virtual ~AlarmInstance();
+
+ private:
+  virtual void HandleMessage(const char* msg);
+  virtual void HandleSyncMessage(const char* msg);
+
+  void HandleAddAbsoluteAlarm(const picojson::value& msg);
+  void HandleAddRelativeAlarm(const picojson::value& msg);
+  void HandleGetRemainingSeconds(const picojson::value& msg);
+  void HandleGetNextScheduledDate(const picojson::value& msg);
+  void HandleGetAlarm(const picojson::value& msg);
+  void HandleGetAllAlarms();
+  void HandleRemoveAlarm(const picojson::value& msg);
+  void HandleRemoveAllAlarms();
+
+  void SendSyncMessage(int err_code, const picojson::value& data);
+
+  std::unique_ptr<AlarmManager> alarm_manager_;
+};
+
+#endif  // ALARM_ALARM_INSTANCE_H_
diff --git a/alarm/alarm_manager.cc b/alarm/alarm_manager.cc
new file mode 100644 (file)
index 0000000..8c339db
--- /dev/null
@@ -0,0 +1,261 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "alarm/alarm_manager.h"
+
+#include <app.h>
+#include <iostream>
+
+#include "alarm/alarm_info.h"
+
+namespace {
+
+const char kAlarmInfoKey[] = "service.extra.alarm";
+const char kHostAppIdKey[] = "service.extra.hostappid";
+
+bool AlarmIterateCallback(int id, void* userdata) {
+  std::vector<int>* ids = reinterpret_cast<std::vector<int>*>(userdata);
+  ids->push_back(id);
+  return true;
+}
+
+}  // namespace
+
+AlarmManager::AlarmManager() {}
+
+AlarmManager::~AlarmManager() {}
+
+void AlarmManager::SetHostAppId(const std::string &host_app_id) {
+  host_app_id_ = host_app_id;
+}
+
+int AlarmManager::ScheduleAlarm(const std::string& app_id,
+                                AlarmInfo* alarm) const {
+  if (!alarm)
+    return -1;
+
+  service_h service = CreateAppLaunchService(app_id);
+  if (!service)
+    return SERVICE_RESULT_FAILED;
+
+  int ret = StoreAlarmInService(service, alarm);
+  if (ret) {
+    DestoryService(service);
+    std::cerr << "Failed to store the alarm information." << std::endl;
+    return ret;
+  }
+
+  ret = service_add_extra_data(service, kHostAppIdKey, host_app_id_.c_str());
+  if (ret) {
+    DestoryService(service);
+    std::cerr << "Failed to store host application ID." << std::endl;
+    return ret;
+  }
+
+  int alarm_id = 0;
+  if (alarm->type() == AlarmInfo::ABSOLUTE) {
+    time_t tval = static_cast<time_t>(alarm->date());
+    struct tm date_tm = {0};
+    localtime_r(&tval, &date_tm);
+    if (alarm->weekflag()) {
+      ret = alarm_schedule_with_recurrence_week_flag(service, &date_tm,
+          alarm->weekflag(), &alarm_id);
+    } else {
+      ret = alarm_schedule_at_date(service, &date_tm, alarm->period(),
+          &alarm_id);
+    }
+  } else if (alarm->type() == AlarmInfo::RELATIVE) {
+    ret = alarm_schedule_after_delay(service, alarm->delay(),
+        alarm->period(), &alarm_id);
+  }
+  alarm->SetId(alarm_id);
+  DestoryService(service);
+
+  if (ret) {
+    std::cerr << "Failed to schedule an alarm." << std::endl;
+    return ret;
+  }
+
+  return 0;
+}
+
+int AlarmManager::GetNextScheduledDate(int alarm_id, int& output) const {
+  if (!CheckOwnership(alarm_id))
+    return -1;
+
+  struct tm date_tm;
+  int ret = alarm_get_scheduled_date(alarm_id, &date_tm);
+  if (ret)
+    return ret;
+
+  struct tm cur_date_tm;
+  ret = alarm_get_current_time(&cur_date_tm);
+  if (ret)
+    return ret;
+
+  int next = mktime(&date_tm);
+  if (next < mktime(&cur_date_tm))
+    return -1;
+
+  output = next;
+  return 0;
+}
+
+int AlarmManager::GetRemainingSeconds(int alarm_id, int& output) const {
+  if (!CheckOwnership(alarm_id))
+    return -1;
+
+  struct tm date_tm;
+  int ret = alarm_get_scheduled_date(alarm_id, &date_tm);
+  if (ret)
+    return ret;
+
+  struct tm cur_date_tm;
+  ret = alarm_get_current_time(&cur_date_tm);
+  if (ret)
+    return ret;
+
+  int next = static_cast<int>(mktime(&date_tm));
+  int current = static_cast<int>(mktime(&cur_date_tm));
+  if (next < current)
+    return -1;
+
+  output = next - current;
+  return 0;
+}
+
+int AlarmManager::RemoveAlarm(int alarm_id) const {
+  service_h service = 0;
+  int ret = alarm_get_service(alarm_id, &service);
+  if (ret)
+    return ret;
+
+  if (!CheckOwnership(service)) {
+    DestoryService(service);
+    return -1;
+  }
+
+  ret = alarm_cancel(alarm_id);
+  DestoryService(service);
+  return ret;
+}
+
+int AlarmManager::RemoveAllAlarms() const {
+  std::vector<int> alarm_ids;
+  int ret = alarm_foreach_registered_alarm(AlarmIterateCallback, &alarm_ids);
+  if (ret)
+    return ret;
+
+  for (int i = 0; i < alarm_ids.size(); i++) {
+    RemoveAlarm(alarm_ids[i]);
+  }
+  return 0;
+}
+
+int AlarmManager::GetAlarm(int alarm_id, AlarmInfo* alarm) const {
+  if (!alarm)
+    return -1;
+
+  service_h service = NULL;
+  int ret = alarm_get_service(alarm_id, &service);
+  if (ret)
+    return ret;
+
+  if (!CheckOwnership(service)) {
+    DestoryService(service);
+    return -1;
+  }
+
+  ret = RestoreAlarmFromService(service, alarm);
+  alarm->SetId(alarm_id);
+
+  DestoryService(service);
+  return ret;
+}
+
+int AlarmManager::GetAllAlarms(
+    std::vector<std::shared_ptr<AlarmInfo> >& output) const {
+  std::vector<int> alarm_ids;
+  int ret = alarm_foreach_registered_alarm(AlarmIterateCallback, &alarm_ids);
+  if (ret)
+    return ret;
+
+  for (int i = 0; i < alarm_ids.size(); i++) {
+    std::shared_ptr<AlarmInfo> alarm(new AlarmInfo());
+    if (GetAlarm(alarm_ids[i], alarm.get()) == 0)
+      output.push_back(alarm);
+  }
+
+  return 0;
+}
+
+service_h
+AlarmManager::CreateAppLaunchService(const std::string& app_id) const {
+  service_h service = 0;
+  if (service_create(&service)) {
+    std::cerr << "Failed to call service_create()" << std::endl;
+    return 0;
+  }
+
+  service_set_app_id(service, app_id.c_str());
+  service_set_operation(service, SERVICE_OPERATION_DEFAULT);
+  return service;
+}
+
+void AlarmManager::DestoryService(service_h service) const {
+  if (service_destroy(service))
+    std::cerr << "Failed to call service_destroy()" << std::endl;
+}
+
+int AlarmManager::StoreAlarmInService(service_h service,
+                                      AlarmInfo* alarm) const {
+  if (!service || !alarm)
+    return -1;
+
+  return service_add_extra_data(service, kAlarmInfoKey,
+      alarm->Serialize().c_str());
+}
+
+int AlarmManager::RestoreAlarmFromService(service_h service,
+                                          AlarmInfo* alarm) const {
+  if (!service || !alarm)
+    return -1;
+
+  char* buffer = NULL;
+  int ret = service_get_extra_data(service, kAlarmInfoKey, &buffer);
+  if (ret)
+    return ret;
+
+  if (!alarm->Deserialize(buffer)) {
+    ret = -1;
+  }
+
+  free(buffer);
+  return ret;
+}
+
+// Return true if the alarm is created by this application.
+// Otherwise return false.
+bool AlarmManager::CheckOwnership(int alarm_id) const {
+  service_h service = NULL;
+  int ret = alarm_get_service(alarm_id, &service);
+  if (ret)
+    return false;
+
+  bool passed = CheckOwnership(service);
+  DestoryService(service);
+
+  return passed;
+}
+
+bool AlarmManager::CheckOwnership(service_h service) const {
+  char* buffer = NULL;
+  if (!service || service_get_extra_data(service, kHostAppIdKey, &buffer))
+    return false;
+
+  bool passed = (host_app_id_ == std::string(buffer));
+  free(buffer);
+
+  return passed;
+}
diff --git a/alarm/alarm_manager.h b/alarm/alarm_manager.h
new file mode 100644 (file)
index 0000000..5c401a7
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ALARM_ALARM_MANAGER_H_
+#define ALARM_ALARM_MANAGER_H_
+
+#include <app_service.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+class AlarmInfo;
+
+class AlarmManager {
+ public:
+  AlarmManager();
+  ~AlarmManager();
+
+  void SetHostAppId(const std::string &host_app_id);
+  int ScheduleAlarm(const std::string& app_id, AlarmInfo* alarm) const;
+  int GetNextScheduledDate(int alarm_id, int& output) const;
+  int GetRemainingSeconds(int alarm_id, int& output) const;
+  int RemoveAlarm(int alarm_id) const;
+  int RemoveAllAlarms() const;
+  int GetAlarm(int alarm_id, AlarmInfo* alarm) const;
+  int GetAllAlarms(std::vector<std::shared_ptr<AlarmInfo> >& output) const;
+
+ private:
+  service_h CreateAppLaunchService(const std::string& app_id) const;
+  void DestoryService(service_h service) const;
+  int StoreAlarmInService(service_h service, AlarmInfo* alarm) const;
+  int RestoreAlarmFromService(service_h service, AlarmInfo* alarm) const;
+  bool CheckOwnership(int alarm_id) const;
+  bool CheckOwnership(service_h service) const;
+
+  std::string host_app_id_;
+};
+
+#endif  // ALARM_ALARM_MANAGER_H_
diff --git a/examples/alarm.html b/examples/alarm.html
new file mode 100644 (file)
index 0000000..9add89c
--- /dev/null
@@ -0,0 +1,126 @@
+<html>
+<head><h1>Hello, Alarm API</h1></head>
+<body>
+<hr>
+<h3>Launch Application at date</h3>
+Application Id: <input type="text" id="appId1" value="xwalk."></input> <br>
+At date: <input type="text" id="scheduledAt"></input><br>
+Period: <input type="text" id="period1" value="0">seconds</input><br>
+<input type="button" value="Launch" onclick="LaunchAtDate()"></input>
+
+<br><br>
+<hr>
+<h3>Launch Application after delay</h3>
+Application Id:<input type="text" id="appId2" value="xwalk."></input> <br>
+After Delay: <input type="text" id="afterDelay" value="1">seconds</input><br>
+Period: <input type="text" id="period2" value="0">seconds</input><br>
+<input type="button" value="Launch" onclick="LaunchAfterDelay()"></input>
+
+<br><br>
+<hr>
+<h3>Get alarm information</h3>
+Alarm Id:<input type="text" id="alarmIdToGet"><br>
+<input type="button" value="query" onclick="GetAlarmInfo()"><br>
+<textarea id="alarmInfoArea" rows="10" cols="64">no alarm found</textarea><br>
+
+<br><br>
+<hr>
+<h3>Remove alarm(s)</h3>
+Alarm Id:<input type="text" id="alarmIdToRemove"><br>
+<input type="button" value="remove" onclick="RemoveAlarm()"><br>
+<textarea id="removeFeedback" rows="10" cols="64"></textarea><br>
+
+<pre id="console"></pre>
+<script src="js/js-test-pre.js"></script>
+<script>
+  var now = new Date();
+  document.getElementById('scheduledAt').value = now.toString();
+
+  function LaunchAtDate() {
+    try {
+      var appId = document.getElementById('appId1').value;
+      var atDate = new Date(document.getElementById('scheduledAt').value);
+      var period = Number.parseInt(document.getElementById('period1').value);
+      //period = period * tizen.alarm.PERIOD_MINUTE;
+      var alarm = new tizen.AlarmAbsolute(atDate, period);
+      if (alarm instanceof tizen.Alarm && alarm instanceof tizen.AlarmAbsolute) {
+        console.log('It is an absolute alarm.');
+      }
+      tizen.alarm.add(alarm, appId);
+      console.log('Alarm:'+JSON.stringify(alarm));
+    } catch (e) {
+      debug(e.name);
+    }
+  }
+
+  function LaunchAfterDelay() {
+    try {
+      var appId = document.getElementById('appId2').value;
+      var delay = Number.parseInt(document.getElementById('afterDelay').value);
+      var period = Number.parseInt(document.getElementById('period2').value);
+      //period = period * tizen.alarm.PERIOD_MINUTE;
+      var alarm = new tizen.AlarmRelative(delay, period);
+      if (alarm instanceof tizen.Alarm && alarm instanceof tizen.AlarmRelative) {
+        console.log('It is a relative alarm.');
+      }
+      tizen.alarm.add(alarm, appId);
+      console.log('Alarm:' + JSON.stringify(alarm));
+    } catch (e) {
+      debug(e.name);
+    }
+  }
+
+  function GetAlarmInfo() {
+    try {
+      var alarmId = Number.parseInt(document.getElementById('alarmIdToGet').value);
+      document.getElementById('alarmInfoArea').value = 'Begin querying alarm.';
+      var output = '';
+      if (!alarmId || isNaN(alarmId)) {
+        var alarms = tizen.alarm.getAll();
+        if (!alarms || alarms.length === 0) {
+          output = 'No alarm is found';
+        } else {
+          for (var i = 0, len = alarms.length; i < len; i++) {
+            output += 'No.' + i + ':' + JSON.stringify(alarms[i]) + '\n';
+          }
+        }
+      } else {
+        var alarm = tizen.alarm.get(alarmId);
+        if (alarm) {
+          output = JSON.stringify(alarm);
+          if (alarm instanceof tizen.AlarmRelative) {
+            output += '\n remaining seconds:' + alarm.getRemainingSeconds();
+          } else if (alarm instanceof tizen.AlarmAbsolute) {
+            output += '\n next Scheduled Date:' + alarm.getNextScheduledDate();
+          }
+        } else {
+          output = 'The alarm is not found.';
+        }
+      }
+      document.getElementById('alarmInfoArea').value = output;
+    }catch(e) {
+      debug(e.name);
+      console.debug(JSON.stringify(e));
+    }
+  }
+
+  function RemoveAlarm() {
+    try {
+      var alarmId = Number.parseInt(document.getElementById('alarmIdToRemove').value);
+      document.getElementById('removeFeedback').value = 'Begin removing alarms.';
+      if (!alarmId || isNaN(alarmId)) {
+        tizen.alarm.removeAll();
+        document.getElementById('removeFeedback').value = 'All alarms have been removed.';
+      } else {
+        tizen.alarm.remove(alarmId);
+        document.getElementById('removeFeedback').value = 'The alarm ' + alarmId + ' has been removed.';
+      }
+    } catch (e) {
+      debug(e.name);
+      console.debug(JSON.stringify(e));
+    }
+  }
+
+</script>
+</body>
+</html>
index 28fe5b0..b569a4a 100644 (file)
@@ -35,5 +35,6 @@ div.block {
 <a href="audiosystem.html"><div class="block">audiosystem</div></a>
 <a href="content.html"><div class="block">content</div></a>
 <a href="speech.html"><div class="block">speech</div></a>
+<a href="alarm.html"><div class="block">alarm</div></a>
 </body>
 </html>
index b6c3554..0c339e3 100644 (file)
@@ -24,6 +24,7 @@
       'conditions': [
         [ 'tizen == 1', {
           'dependencies': [
+            'alarm/alarm.gyp:*',
             'application/application.gyp:*',
             'audiosystem/audiosystem.gyp:*',
             'bookmark/bookmark.gyp:*',