Update change log and spec for wrt-plugins-tizen_0.4.70
[framework/web/wrt-plugins-tizen.git] / src / Alarm / JSAlarmManager.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an AS IS BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18
19 #include <vector>
20 #include <app.h>
21 #include <time.h>
22 #include <string>
23
24 #include <CommonsJavaScript/Converter.h>
25 #include <CommonsJavaScript/Validator.h>
26 #include <CommonsJavaScript/JSUtils.h>
27 #include <CommonsJavaScript/JSDOMExceptionFactory.h>
28
29 #include <ArgumentValidator.h>
30 #include <JSUtil.h>
31 #include <Security.h>
32
33 #include <SecurityExceptions.h>
34 #include <Commons/Exception.h>
35 #include <Commons/Regex.h>
36 #include <JSWebAPIErrorFactory.h>
37 #include <JSApplicationControl.h>
38 #include <ApplicationControl.h>
39 #include <ApplicationConverter.h>
40
41 #include <ail.h>
42
43 #include "plugin_config_impl.h"
44 #include "AlarmConverter.h"
45 #include "JSAlarmAbsolute.h"
46 #include "AlarmAbsolute.h"
47 #include "JSAlarmRelative.h"
48 #include "AlarmRelative.h"
49 #include "JSAlarmManager.h"
50
51 #include <TimeTracer.h>
52 #include <Export.h>
53 #include <Logger.h>
54
55 namespace DeviceAPI {
56 namespace Alarm {
57
58 using namespace WrtDeviceApis::Commons;
59 using namespace WrtDeviceApis::CommonsJavaScript;
60 using namespace DeviceAPI::Common;
61
62 static bool alarm_iterate_callback(int alarm_id, void *user_data)
63 {
64     std::vector<int> *alarmIds = reinterpret_cast<std::vector<int>*>(user_data);
65    
66     alarmIds->push_back(alarm_id);
67     return true;
68 }
69
70 JSClassRef JSAlarmManager::m_jsClassRef = NULL;
71
72 JSClassDefinition JSAlarmManager::m_jsClassInfo = {
73         0,
74         kJSClassAttributeNone,
75         TIZEN_ALARM_INTERFACE,
76         NULL,
77         m_property,
78         m_function,
79         initialize,
80         finalize,
81         NULL, //hasProperty,
82         NULL, //getProperty,
83         NULL, //setProperty,
84         NULL, //deleteProperty,Geolocation
85         NULL, //getPropertyNames,
86         NULL,
87         NULL, // constructor
88         NULL,
89         NULL
90 };
91
92 JSStaticFunction JSAlarmManager::m_function[] = {    
93         { ALARM_FUNCTION_API_ADD, JSAlarmManager::add,kJSPropertyAttributeNone },
94         { ALARM_FUNCTION_API_REMOVE, JSAlarmManager::remove,kJSPropertyAttributeNone },
95         { ALARM_FUNCTION_API_REMOVE_ALL, JSAlarmManager::removeAll,kJSPropertyAttributeNone },
96         { ALARM_FUNCTION_API_GET_ALL, JSAlarmManager::getAll,kJSPropertyAttributeNone },
97         { ALARM_FUNCTION_API_GET, JSAlarmManager::get,kJSPropertyAttributeNone },
98         { 0, 0, 0 }
99 };
100
101 JSStaticValue JSAlarmManager::m_property[] = {
102         { TIZEN_ALARM_CONSTANT_PERIOD_MINUTE, getProperty, NULL, kJSPropertyAttributeReadOnly },
103         { TIZEN_ALARM_CONSTANT_PERIOD_HOUR, getProperty, NULL, kJSPropertyAttributeReadOnly },
104         { TIZEN_ALARM_CONSTANT_PERIOD_DAY, getProperty, NULL, kJSPropertyAttributeReadOnly },
105         { TIZEN_ALARM_CONSTANT_PERIOD_WEEK, getProperty, NULL, kJSPropertyAttributeReadOnly },
106         { 0, 0, 0, 0 }
107 };
108
109 const JSClassRef DLL_EXPORT JSAlarmManager::getClassRef()
110 {
111     if (!m_jsClassRef) {
112         m_jsClassRef = JSClassCreate(&m_jsClassInfo);
113     }
114     return m_jsClassRef;
115 }
116
117 const JSClassDefinition* JSAlarmManager::getClassInfo() 
118 {
119     return &m_jsClassInfo;
120 }
121
122 JSContextRef JSAlarmManager::gContext = NULL;
123
124 void JSAlarmManager::initialize(JSContextRef ctx, JSObjectRef object) 
125 {
126     gContext = ctx;
127
128     SecurityAccessor *priv = new SecurityAccessor();
129         JSObjectSetPrivate(object, static_cast<void*>(priv));
130 }
131
132 void JSAlarmManager::finalize(JSObjectRef object) 
133 {
134         SecurityAccessor *priv = static_cast<SecurityAccessor*>(JSObjectGetPrivate(object));
135         delete priv;
136 }
137
138 JSValueRef JSAlarmManager::add(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
139 {
140     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
141     service_h service;
142     struct tm startDate;
143     int delay = 0;
144     int alarm_id;
145     std::string applicationId;
146     std::string page;
147
148     SecurityAccessor *thisPriv = static_cast<SecurityAccessor*>(JSObjectGetPrivate(thisObject));
149     if (!thisPriv) {
150         LoggerE("private object is null");
151         return JSWebAPIErrorFactory::postException(ctx, exception,
152                 JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Wrong object");
153     }
154     TIME_TRACER_ITEM_BEGIN("(add)ace_check", 0);
155     TIZEN_CHECK_ACCESS(ctx, exception, thisPriv, ALARM_FUNCTION_API_ADD);
156     TIME_TRACER_ITEM_END("(add)ace_check", 0);
157
158     try {
159         ArgumentValidator validator(ctx, argumentCount, arguments);
160         AlarmConverter converter(ctx);
161         
162         // applicationId
163         std::string appId = validator.toString(1);
164
165         // alarm
166         JSObjectRef alarmObj = validator.toObject(0);
167         if (JSValueIsObjectOfClass(ctx, alarmObj, JSAlarmAbsolute::getClassRef())) {
168
169             JSAlarmAbsolutePriv *priv = static_cast<JSAlarmAbsolutePriv*>(JSObjectGetPrivate(alarmObj));
170             if (!priv) {
171                 throw TypeMismatchException("Object is null.");
172             }
173             AlarmAbsolutePtr alarmPtr = priv->getObject();
174             if (!alarmPtr) {
175                 throw TypeMismatchException("Private object is null.");
176             }
177     
178             startDate = alarmPtr->getDate();
179             service = alarmPtr->getService();
180             service_set_app_id(service, appId.c_str());
181             
182             // appControl
183             JSObjectRef appControlObj = validator.toObject(2, true);
184             if (appControlObj) {
185                 if(!JSValueIsObjectOfClass(ctx, appControlObj, DeviceAPI::Application::JSApplicationControl::getClassRef())) {
186                     throw TypeMismatchException("Third parameter is not a ApplicationControl object");
187                 }
188                 DeviceAPI::Application::ApplicationConverter applicationConverter(ctx);
189                 DeviceAPI::Application::ApplicationControlPtr appService = applicationConverter.toApplicationControl(appControlObj);
190                 if(converter.toAlarmService(service, appService) == false) {
191                     throw TypeMismatchException("Third parameter is not a ApplicationControl object");
192                 }
193             } else {
194                 service_set_operation(service, SERVICE_OPERATION_DEFAULT);
195             }
196
197             AbsoluteRecurrence::Type alarmType = alarmPtr->getRecurrenceType();
198
199             int err = ALARM_ERROR_NONE;
200             if(alarmType == AbsoluteRecurrence::ByDayValue) {
201                 int bydayValue = converter.toNativeAlarmValue(alarmPtr->getByDayRecurrence());
202                 LoggerI("Native bydayValue = " << bydayValue);
203                 TIME_TRACER_ITEM_BEGIN("(add)alarm_schedule_with_recurrence_week_flag", 0);
204                 err = alarm_schedule_with_recurrence_week_flag(service, &startDate, bydayValue, &alarm_id);
205                 TIME_TRACER_ITEM_END("(add)alarm_schedule_with_recurrence_week_flag", 0);
206
207             } else if(alarmType == AbsoluteRecurrence::Interval) {
208                 int interval = alarmPtr->getInterval();
209                 TIME_TRACER_ITEM_BEGIN("(add)alarm_schedule_at_date", 0);
210                 err = alarm_schedule_at_date(service, &startDate, interval, &alarm_id);
211                 TIME_TRACER_ITEM_END("(add)alarm_schedule_at_date", 0);
212             } else {
213                 TIME_TRACER_ITEM_BEGIN("(add)alarm_schedule_at_date", 0);
214                 err = alarm_schedule_at_date(service, &startDate, 0, &alarm_id);
215                 TIME_TRACER_ITEM_END("(add)alarm_schedule_at_date", 0);
216             }
217
218             if(err == ALARM_ERROR_NONE) {
219                 alarmPtr->setId(alarm_id);
220             } else {
221                 throw UnknownException("Alarm scheduling failed.");
222             }
223             
224         } else if (JSValueIsObjectOfClass(ctx, alarmObj, JSAlarmRelative::getClassRef())) {
225
226             JSAlarmRelativePriv *priv = static_cast<JSAlarmRelativePriv*>(JSObjectGetPrivate(alarmObj));
227             if (!priv) {
228                 throw TypeMismatchException("Object is null.");
229             }
230             AlarmRelativePtr alarmPtr = priv->getObject();
231             if (!alarmPtr) {
232                 throw TypeMismatchException("Private object is null.");
233             }
234
235             delay = alarmPtr->getDelay();
236             if (delay < 0) {
237                 throw InvalidValuesException("Alarm scheduling failed : delay cannot be negative value.");
238             }
239
240             long interval = alarmPtr->getPeriod();
241             service = alarmPtr->getService();
242             service_set_app_id(service, appId.c_str());
243
244             // appControl
245             JSObjectRef appControlObj = validator.toObject(2, true);
246             if (appControlObj) {
247                 if(!JSValueIsObjectOfClass(ctx, appControlObj, DeviceAPI::Application::JSApplicationControl::getClassRef())) {
248                     throw TypeMismatchException("Third parameter is not a ApplicationControl object");
249                 }
250                 DeviceAPI::Application::ApplicationConverter applicationConverter(ctx);
251                 DeviceAPI::Application::ApplicationControlPtr appService = applicationConverter.toApplicationControl(appControlObj);
252                 if(converter.toAlarmService(service, appService) == false) {
253                     throw TypeMismatchException("Third parameter is not a ApplicationControl object");
254                 }
255             } else {
256                 service_set_operation(service, SERVICE_OPERATION_DEFAULT);
257             }
258
259             TIME_TRACER_ITEM_BEGIN("(add)alarm_schedule_after_delay", 0);
260             int err = alarm_schedule_after_delay(service, delay, interval, &alarm_id);
261             TIME_TRACER_ITEM_END("(add)alarm_schedule_after_delay", 0);
262
263             if(err == ALARM_ERROR_NONE) {
264                 alarmPtr->setId(alarm_id);
265             } else {
266                 throw UnknownException("Alarm scheduling failed.");
267             }
268
269         } else {
270             LoggerE("First parameter is not a Alarm object");
271             throw TypeMismatchException("First parameter is not a Alarm object");
272         }
273         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
274         return JSValueMakeUndefined(ctx);
275
276     }  catch (const BasePlatformException &err) {
277         return JSWebAPIErrorFactory::postException(ctx, exception, err);
278     } catch (...) {
279         DeviceAPI::Common::UnknownException err("Unknown Error in ApplicationManager.getAppSharedURI().");
280         return JSWebAPIErrorFactory::postException(ctx, exception, err);
281     }
282 }
283
284 JSValueRef JSAlarmManager::remove(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
285 {
286     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
287     SecurityAccessor *thisPriv = static_cast<SecurityAccessor*>(JSObjectGetPrivate(thisObject));
288     if (!thisPriv) {
289         LoggerE("private object is null");
290         return JSWebAPIErrorFactory::postException(ctx, exception,
291                 JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Wrong object");
292     }
293     TIME_TRACER_ITEM_BEGIN("(add)ace_check", 0);
294     TIZEN_CHECK_ACCESS(ctx, exception, thisPriv, ALARM_FUNCTION_API_REMOVE);
295     TIME_TRACER_ITEM_END("(add)ace_check", 0);
296     
297     try {
298         ArgumentValidator validator(ctx, argumentCount, arguments);
299
300         // id
301         std::string id = validator.toString(0);
302         
303         int alarmId = 0;
304         std::stringstream(id) >> alarmId;
305
306         if (alarmId <= 0) {
307             throw InvalidValuesException("Invalid ID");
308         }
309
310         TIME_TRACER_ITEM_BEGIN("(remove)alarm_cancel", 0);
311         int ret = alarm_cancel(alarmId);
312         TIME_TRACER_ITEM_END("(remove)alarm_cancel", 0);
313
314         if (ret != ALARM_ERROR_NONE) {
315             throw NotFoundException("Alarm not found");
316         }
317         
318         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
319         return JSValueMakeUndefined(ctx);
320     } catch (const BasePlatformException &err) {
321         return JSWebAPIErrorFactory::postException(ctx, exception, err);
322     } catch (...) {
323         DeviceAPI::Common::UnknownException err("Unknown Error in ApplicationManager.getAppSharedURI().");
324         return JSWebAPIErrorFactory::postException(ctx, exception, err);
325     }
326 }
327
328 JSValueRef JSAlarmManager::removeAll(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
329 {
330     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
331     SecurityAccessor *thisPriv = static_cast<SecurityAccessor*>(JSObjectGetPrivate(thisObject));
332     if (!thisPriv) {
333         LoggerE("private object is null");
334         return JSWebAPIErrorFactory::postException(ctx, exception,
335                 JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Wrong object");
336     }
337     TIME_TRACER_ITEM_BEGIN("(add)ace_check", 0);
338     TIZEN_CHECK_ACCESS(ctx, exception, thisPriv, ALARM_FUNCTION_API_REMOVE_ALL);
339     TIME_TRACER_ITEM_END("(add)ace_check", 0);
340
341     TIME_TRACER_ITEM_BEGIN("(removeAll)alarm_cancel_all", 0);
342     int returnVal = alarm_cancel_all();
343     TIME_TRACER_ITEM_END("(removeAll)alarm_cancel_all", 0);
344
345     if (ALARM_ERROR_NONE != returnVal) {
346         LoggerE("Error while removing all alarms: "<< returnVal);
347     }
348
349     TIME_TRACER_ITEM_END(__FUNCTION__, 0);
350     return JSValueMakeUndefined(ctx);
351 }
352
353 JSValueRef JSAlarmManager::get(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
354 {
355     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
356     try {
357         service_h service = NULL;
358         char* alarmType = NULL;
359         JSValueRef result = NULL;
360         
361         ArgumentValidator validator(ctx, argumentCount, arguments);
362         AlarmConverter converter(ctx);
363
364         // id
365         std::string id = validator.toString(0);
366         int alarmId = 0;
367         std::stringstream(id) >> alarmId;   
368
369         if (alarmId <= 0) {
370             LoggerE("Wrong Alarm ID");
371             throw InvalidValuesException("Invalid ID");
372         }
373
374         TIME_TRACER_ITEM_BEGIN("(get)alarm_get_service", 0);
375         int ret = alarm_get_service(alarmId, &service);
376
377         if (ret != ALARM_ERROR_NONE) {
378             throw NotFoundException("Alarm not found");
379         }
380         
381         ret = service_get_extra_data(service, ALARM_TYPE_KEY, &alarmType);
382         if (ret != SERVICE_ERROR_NONE) {
383             LoggerE("Getting data failed: " << ret);
384             service_destroy(service);
385             throw UnknownException("Unknown error occurred.");
386         }
387         TIME_TRACER_ITEM_END("(get)alarm_get_service", 0);
388         
389         if (strcmp(alarmType, ALARM_TYPE_ABSOLUTE_VALUE) == 0) {
390             AlarmAbsolutePtr privateData = AlarmAbsolutePtr(new AlarmAbsolute(service));
391             
392             if(!converter.toAlarmAbsolutePtr(alarmId, service, privateData)) {
393                 service_destroy(service);
394                 throw TypeMismatchException("Alarm not found");
395             }
396
397             result = JSAlarmAbsolute::createJSObject(ctx, privateData);     
398
399         } else if(strcmp(alarmType, ALARM_TYPE_RELATIVE_VALUE) == 0) {
400             AlarmRelativePtr privateData = AlarmRelativePtr(new AlarmRelative(service));
401             
402             if(!converter.toAlarmRelativePtr(alarmId, service, privateData)) {
403                 service_destroy(service);
404                  throw TypeMismatchException("Alarm not found");
405             }
406             
407             result = JSAlarmRelative::createJSObject(ctx, privateData);  
408         } else {
409             service_destroy(service);
410             throw UnknownException("Unknown error occurred.");
411         }
412
413         service_destroy(service);
414         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
415         return result;
416     } catch (const BasePlatformException &err) {
417         return JSWebAPIErrorFactory::postException(ctx, exception, err);
418     } catch (...) {
419         DeviceAPI::Common::UnknownException err("Unknown Error in ApplicationManager.getAppSharedURI().");
420         return JSWebAPIErrorFactory::postException(ctx, exception, err);
421     }
422 }
423
424
425 JSValueRef JSAlarmManager::getAll(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
426 {
427     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
428     try {
429         AlarmConverter converter(ctx);
430         std::vector<int> alarmIds; 
431
432         TIME_TRACER_ITEM_BEGIN("(getAll)alarm_foreach_registered_alarm", 0);
433         int error = alarm_foreach_registered_alarm(alarm_iterate_callback, &alarmIds);
434         TIME_TRACER_ITEM_END("(getAll)alarm_foreach_registered_alarm", 0);
435         if (error == ALARM_ERROR_CONNECTION_FAIL) {
436             LoggerE("Alarm system may not be ready yet.");
437             alarmIds.clear();
438         } else if(error != ALARM_ERROR_NONE) {
439             LoggerE("Error occurred while getting all alarms : " << error);
440             throw UnknownException("Unknown error occurred.");
441         }
442
443         JSObjectRef jsResult = JSCreateArrayObject(ctx, 0, NULL);
444         if (jsResult == NULL) {
445             throw TypeMismatchException("Could not create js array object.");
446         }
447
448         for (size_t i = 0 ; i < alarmIds.size(); i++) {
449
450             service_h handle = NULL;
451             char* alarmType = NULL;
452
453             TIME_TRACER_ITEM_BEGIN("(getAll)alarm_get_service", 0);
454             error = alarm_get_service(alarmIds.at(i), &handle);
455             TIME_TRACER_ITEM_END("(getAll)alarm_get_service", 0);
456             if(error != ALARM_ERROR_NONE) {
457                 LoggerE("Getting service failed: " << error);
458                 throw NotFoundException("Alarm not found");
459             }
460
461             TIME_TRACER_ITEM_BEGIN("(getAll)service_get_extra_data", 0);
462             error = service_get_extra_data(handle, ALARM_TYPE_KEY, &alarmType);
463             TIME_TRACER_ITEM_END("(getAll)service_get_extra_data", 0);
464             if(error != SERVICE_ERROR_NONE) {
465                 LoggerI("Getting data failed: " << error);
466                 service_destroy(handle);
467                 throw UnknownException("Unknown error occurred.");
468             }
469
470             JSValueRef obj = NULL;
471             if (strcmp(alarmType, ALARM_TYPE_ABSOLUTE_VALUE) == 0) {
472                 AlarmAbsolutePtr privateData = AlarmAbsolutePtr(new AlarmAbsolute(handle));
473
474                 if(!converter.toAlarmAbsolutePtr(alarmIds.at(i), handle, privateData)) {
475                     service_destroy(handle);
476                     throw TypeMismatchException("Absolute alarm conversion failed.");
477                 }
478
479                 obj = JSAlarmAbsolute::createJSObject(ctx, privateData);
480                 
481             } else if( !strcmp(alarmType, ALARM_TYPE_RELATIVE_VALUE)) {
482                 AlarmRelativePtr privateData = AlarmRelativePtr(new AlarmRelative(handle));
483                 
484                 if(!converter.toAlarmRelativePtr(alarmIds.at(i), handle, privateData)) {
485                     service_destroy(handle);
486                     throw TypeMismatchException("Relative alarm conversion failed.");
487                 }
488                 obj = JSAlarmRelative::createJSObject(ctx, privateData);
489
490             }  else {
491                 service_destroy(handle);
492                 throw UnknownException("Unknown error occurred.");
493             }
494
495             service_destroy(handle);
496             
497             if(!JSSetArrayElement(ctx, jsResult, i, obj)) {
498                 service_destroy(handle);
499                 throw UnknownException("JS array creation failed.");
500             }
501         }
502
503         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
504         return jsResult;
505     } catch (const BasePlatformException &err) {
506         return JSWebAPIErrorFactory::postException(ctx, exception, err);
507     } catch (...) {
508         DeviceAPI::Common::UnknownException err("Unknown Error in ApplicationManager.getAppSharedURI().");
509         return JSWebAPIErrorFactory::postException(ctx, exception, err);
510     }
511 }
512
513 JSValueRef JSAlarmManager::getProperty(JSContextRef context,
514         JSObjectRef object,
515         JSStringRef propertyName,
516         JSValueRef* exception)
517 {
518     try {
519         if (JSStringIsEqualToUTF8CString(propertyName, TIZEN_ALARM_CONSTANT_PERIOD_MINUTE)) {
520             return JSUtil::toJSValueRef(context, (long)60);
521         } else if (JSStringIsEqualToUTF8CString(propertyName, TIZEN_ALARM_CONSTANT_PERIOD_HOUR)) {
522             return JSUtil::toJSValueRef(context, (long)3600);
523         } else if (JSStringIsEqualToUTF8CString(propertyName, TIZEN_ALARM_CONSTANT_PERIOD_DAY)) {
524             return JSUtil::toJSValueRef(context, (long)86400);
525         } else if (JSStringIsEqualToUTF8CString(propertyName, TIZEN_ALARM_CONSTANT_PERIOD_WEEK)) {
526             return JSUtil::toJSValueRef(context, (long)604800);
527         }
528     } catch (const BasePlatformException &err) {
529         LoggerE("Getting property is failed. %s", err.getMessage().c_str());
530     }
531
532     return NULL;
533 }
534
535 } // Alarm
536 } // TizenApis
537