tizen 2.4 release
[framework/context/context-service.git] / src / timer_mgr_impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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 #include <map>
18 #include <alarm.h>
19 #include <scope_mutex.h>
20 #include <timer_mgr.h>
21 #include "timer_mgr_impl.h"
22
23 #define IDENTIFIER "contextd"
24
25 struct listener_info_s {
26         int timer_id;
27         ctx::timer_listener_iface* listener;
28         void* user_data;
29 };
30
31 typedef std::map<alarm_id_t, listener_info_s> listener_map_t;
32 static listener_map_t *listener_map = NULL;
33 static GMutex listener_map_mutex;
34
35 static int generate_timer_id()
36 {
37         static int tid = 0;
38
39         tid ++;
40         if (tid < 0) {
41                 _W("Overflow");
42                 tid = 1;
43         }
44
45         return tid;
46 }
47
48 static int alarm_expired_cb(alarm_id_t alarm_id, void* cb_data)
49 {
50         int timer_id = 0;
51         ctx::timer_listener_iface *listener = NULL;
52         void* user_data;
53
54         {
55                 ctx::scope_mutex sm1(&listener_map_mutex);
56                 listener_map_t::iterator mit = listener_map->find(alarm_id);
57                 IF_FAIL_RETURN_TAG(mit != listener_map->end(), 0, _W, "Unknown Alarm %d", alarm_id);
58                 timer_id = mit->second.timer_id;
59                 listener = mit->second.listener;
60                 user_data = mit->second.user_data;
61         }
62
63         _D("Timer %d expired", timer_id);
64         bool repeat = listener->on_timer_expired(timer_id, user_data);
65
66         if (!repeat) {
67                 _D("Stop repeating Timer %d (Alarm %d)", timer_id, alarm_id);
68                 ctx::scope_mutex sm2(&listener_map_mutex);
69                 alarmmgr_remove_alarm(alarm_id);
70                 listener_map->erase(alarm_id);
71         }
72
73         return 0;
74 }
75
76 ctx::timer_manager_impl::timer_manager_impl()
77         : initialized(false)
78 {
79 }
80
81 ctx::timer_manager_impl::~timer_manager_impl()
82 {
83         release();
84 }
85
86 bool ctx::timer_manager_impl::init()
87 {
88         IF_FAIL_RETURN_TAG(!initialized, true, _W, "Re-initialization");
89
90         listener_map = new(std::nothrow) listener_map_t;
91         IF_FAIL_RETURN_TAG(listener_map, false, _E, "Memory allocation failed");
92
93         int result = alarmmgr_init(IDENTIFIER);
94         IF_FAIL_RETURN_TAG(result == ALARMMGR_RESULT_SUCCESS, false, _E, "Alarm manager initialization failed");
95
96         result = alarmmgr_set_cb(alarm_expired_cb, this);
97         if (result != ALARMMGR_RESULT_SUCCESS) {
98                 alarmmgr_fini();
99                 _E("Alarm callback registration failed");
100                 return false;
101         }
102
103         alarmmgr_remove_all();
104         initialized = true;
105         return true;
106 }
107
108 void ctx::timer_manager_impl::release()
109 {
110         if (initialized) {
111                 alarmmgr_remove_all();
112                 alarmmgr_fini();
113                 delete listener_map;
114                 listener_map = NULL;
115                 initialized = false;
116         }
117 }
118
119 int ctx::timer_manager_impl::set_for(int interval, timer_listener_iface* listener, void* user_data)
120 {
121         IF_FAIL_RETURN_TAG(interval > 0 && listener, false, _E, "Invalid parameter");
122
123         alarm_id_t alarm_id;
124         int result;
125
126 #if 0
127         // Implementation for Tizen 2.3
128         time_t trigger_time;
129         time(&trigger_time);
130         // time_t is in seconds.. It is the POSIX specification.
131         trigger_time += (interval * 60);
132
133         result = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE, trigger_time, interval * 60, NULL, &alarm_id);
134 #endif
135
136         result = alarmmgr_add_periodic_alarm_withcb(interval, QUANTUMIZE, alarm_expired_cb, this, &alarm_id);
137         IF_FAIL_RETURN_TAG(result == ALARMMGR_RESULT_SUCCESS, ERR_OPERATION_FAILED, _E, "Alarm initialization failed");
138
139         ctx::scope_mutex sm(&listener_map_mutex);
140
141         listener_info_s info;
142         info.timer_id = generate_timer_id();
143         info.listener = listener;
144         info.user_data = user_data;
145         (*listener_map)[alarm_id] = info;
146
147         _D("Timer %d was set for %dm interval", info.timer_id, interval);
148
149         return info.timer_id;
150 }
151
152 int ctx::timer_manager_impl::set_at(int hour, int min, int day_of_week, timer_listener_iface* listener, void* user_data)
153 {
154         IF_FAIL_RETURN_TAG(
155                         hour < 24 && hour >= 0 &&
156                         min < 60 && min >= 0 &&
157                         day_of_week > 0 && day_of_week <= timer_manager::EVERYDAY &&
158                         listener, false, _E, "Invalid parameter");
159
160         int repeat = 0;
161         if (day_of_week & timer_manager::SUN) repeat |= ALARM_WDAY_SUNDAY;
162         if (day_of_week & timer_manager::MON) repeat |= ALARM_WDAY_MONDAY;
163         if (day_of_week & timer_manager::TUE) repeat |= ALARM_WDAY_TUESDAY;
164         if (day_of_week & timer_manager::WED) repeat |= ALARM_WDAY_WEDNESDAY;
165         if (day_of_week & timer_manager::THU) repeat |= ALARM_WDAY_THURSDAY;
166         if (day_of_week & timer_manager::FRI) repeat |= ALARM_WDAY_FRIDAY;
167         if (day_of_week & timer_manager::SAT) repeat |= ALARM_WDAY_SATURDAY;
168
169         alarm_entry_t *alarm_info = alarmmgr_create_alarm();
170         IF_FAIL_RETURN_TAG(alarm_info, ERR_OPERATION_FAILED, _E, "Memory allocation failed");
171
172         time_t current_time;
173         struct tm current_tm;
174         time(&current_time);
175         tzset();
176         localtime_r(&current_time, &current_tm);
177
178         alarm_date_t alarm_time;
179         alarm_time.year = current_tm.tm_year + 1900;
180         alarm_time.month = current_tm.tm_mon + 1;
181         alarm_time.day = current_tm.tm_mday;
182         alarm_time.hour = hour;
183         alarm_time.min = min;
184         alarm_time.sec = 0;
185
186         alarmmgr_set_time(alarm_info, alarm_time);
187         alarmmgr_set_repeat_mode(alarm_info, ALARM_REPEAT_MODE_WEEKLY, repeat);
188         alarmmgr_set_type(alarm_info, ALARM_TYPE_VOLATILE);
189
190         alarm_id_t alarm_id;
191         int ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &alarm_id);
192         alarmmgr_free_alarm(alarm_info);
193
194         IF_FAIL_RETURN_TAG(ret == ALARMMGR_RESULT_SUCCESS, ERR_OPERATION_FAILED, _E, "Alarm initialization failed");
195
196         ctx::scope_mutex sm(&listener_map_mutex);
197
198         listener_info_s info;
199         info.timer_id = generate_timer_id();
200         info.listener = listener;
201         info.user_data = user_data;
202
203         (*listener_map)[alarm_id] = info;
204
205         _D("Timer %d was set at %02d:%02d:00 (day of week: %#x)", info.timer_id, hour, min, day_of_week);
206
207         return info.timer_id;
208 }
209
210 void ctx::timer_manager_impl::remove(int timer_id)
211 {
212         ctx::scope_mutex sm(&listener_map_mutex);
213
214         listener_map_t::iterator it;
215         for (it = listener_map->begin(); it != listener_map->end(); ++it) {
216                 if (it->second.timer_id == timer_id) {
217                         alarmmgr_remove_alarm(it->first);
218                         listener_map->erase(it);
219                         _D("Timer %d was removed", timer_id);
220                         break;
221                 }
222         }
223 }