OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/api/alarms/alarm_manager.h" | 5 #include "chrome/browser/extensions/api/alarms/alarm_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/json/json_writer.h" | 8 #include "base/json/json_writer.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 | 25 |
26 // The minimum period between polling for alarms to run. | 26 // The minimum period between polling for alarms to run. |
27 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromMinutes(5); | 27 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromMinutes(5); |
28 | 28 |
29 class DefaultAlarmDelegate : public AlarmManager::Delegate { | 29 class DefaultAlarmDelegate : public AlarmManager::Delegate { |
30 public: | 30 public: |
31 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {} | 31 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {} |
32 virtual ~DefaultAlarmDelegate() {} | 32 virtual ~DefaultAlarmDelegate() {} |
33 | 33 |
34 virtual void OnAlarm(const std::string& extension_id, | 34 virtual void OnAlarm(const std::string& extension_id, |
35 const AlarmManager::Alarm& alarm) { | 35 const Alarm& alarm) { |
36 ListValue args; | 36 ListValue args; |
37 std::string json_args; | 37 std::string json_args; |
38 args.Append(alarm.ToValue().release()); | 38 args.Append(alarm.js_alarm->ToValue().release()); |
39 base::JSONWriter::Write(&args, &json_args); | 39 base::JSONWriter::Write(&args, &json_args); |
40 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( | 40 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( |
41 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); | 41 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); |
42 } | 42 } |
43 | 43 |
44 private: | 44 private: |
45 Profile* profile_; | 45 Profile* profile_; |
46 }; | 46 }; |
47 | 47 |
48 // Creates a TimeDelta from a delay as specified in the API. | 48 // Creates a TimeDelta from a delay as specified in the API. |
49 base::TimeDelta TimeDeltaFromDelay(double delay_in_minutes) { | 49 base::TimeDelta TimeDeltaFromDelay(double delay_in_minutes) { |
50 return base::TimeDelta::FromMicroseconds( | 50 return base::TimeDelta::FromMicroseconds( |
51 delay_in_minutes * base::Time::kMicrosecondsPerMinute); | 51 delay_in_minutes * base::Time::kMicrosecondsPerMinute); |
52 } | 52 } |
53 | 53 |
54 } // namespace | 54 } // namespace |
55 | 55 |
56 // AlarmManager | 56 // AlarmManager |
57 | 57 |
58 AlarmManager::AlarmManager(Profile* profile) | 58 AlarmManager::AlarmManager(Profile* profile, TimeProvider now) |
59 : profile_(profile), | 59 : profile_(profile), |
| 60 now_(now), |
60 delegate_(new DefaultAlarmDelegate(profile)), | 61 delegate_(new DefaultAlarmDelegate(profile)), |
61 last_poll_time_(base::Time()) { | 62 last_poll_time_(base::Time()) { |
62 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | 63 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
63 content::Source<Profile>(profile_)); | 64 content::Source<Profile>(profile_)); |
64 } | 65 } |
65 | 66 |
66 AlarmManager::~AlarmManager() { | 67 AlarmManager::~AlarmManager() { |
67 } | 68 } |
68 | 69 |
69 void AlarmManager::AddAlarm(const std::string& extension_id, | 70 void AlarmManager::AddAlarm(const std::string& extension_id, |
70 const linked_ptr<Alarm>& alarm) { | 71 const Alarm& alarm) { |
71 base::TimeDelta alarm_time = TimeDeltaFromDelay(alarm->delay_in_minutes); | 72 AddAlarmImpl(extension_id, alarm); |
72 AddAlarmImpl(extension_id, alarm, alarm_time); | |
73 WriteToPrefs(extension_id); | 73 WriteToPrefs(extension_id); |
74 } | 74 } |
75 | 75 |
76 const AlarmManager::Alarm* AlarmManager::GetAlarm( | 76 const Alarm* AlarmManager::GetAlarm( |
77 const std::string& extension_id, const std::string& name) { | 77 const std::string& extension_id, const std::string& name) { |
78 AlarmIterator it = GetAlarmIterator(extension_id, name); | 78 AlarmIterator it = GetAlarmIterator(extension_id, name); |
79 if (it.first == alarms_.end()) | 79 if (it.first == alarms_.end()) |
80 return NULL; | 80 return NULL; |
81 return it.second->get(); | 81 return &*it.second; |
82 } | 82 } |
83 | 83 |
84 const AlarmManager::AlarmList* AlarmManager::GetAllAlarms( | 84 const AlarmManager::AlarmList* AlarmManager::GetAllAlarms( |
85 const std::string& extension_id) { | 85 const std::string& extension_id) { |
86 AlarmMap::iterator list = alarms_.find(extension_id); | 86 AlarmMap::iterator list = alarms_.find(extension_id); |
87 if (list == alarms_.end()) | 87 if (list == alarms_.end()) |
88 return NULL; | 88 return NULL; |
89 return &list->second; | 89 return &list->second; |
90 } | 90 } |
91 | 91 |
92 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator( | 92 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator( |
93 const std::string& extension_id, const std::string& name) { | 93 const std::string& extension_id, const std::string& name) { |
94 AlarmMap::iterator list = alarms_.find(extension_id); | 94 AlarmMap::iterator list = alarms_.find(extension_id); |
95 if (list == alarms_.end()) | 95 if (list == alarms_.end()) |
96 return make_pair(alarms_.end(), AlarmList::iterator()); | 96 return make_pair(alarms_.end(), AlarmList::iterator()); |
97 | 97 |
98 for (AlarmList::iterator it = list->second.begin(); | 98 for (AlarmList::iterator it = list->second.begin(); |
99 it != list->second.end(); ++it) { | 99 it != list->second.end(); ++it) { |
100 if ((*it)->name == name) | 100 if (it->js_alarm->name == name) |
101 return make_pair(list, it); | 101 return make_pair(list, it); |
102 } | 102 } |
103 | 103 |
104 return make_pair(alarms_.end(), AlarmList::iterator()); | 104 return make_pair(alarms_.end(), AlarmList::iterator()); |
105 } | 105 } |
106 | 106 |
107 bool AlarmManager::RemoveAlarm(const std::string& extension_id, | 107 bool AlarmManager::RemoveAlarm(const std::string& extension_id, |
108 const std::string& name) { | 108 const std::string& name) { |
109 AlarmIterator it = GetAlarmIterator(extension_id, name); | 109 AlarmIterator it = GetAlarmIterator(extension_id, name); |
110 if (it.first == alarms_.end()) | 110 if (it.first == alarms_.end()) |
(...skipping 12 matching lines...) Expand all Loading... |
123 // Note: I'm using indices rather than iterators here because | 123 // Note: I'm using indices rather than iterators here because |
124 // RemoveAlarmIterator will delete the list when it becomes empty. | 124 // RemoveAlarmIterator will delete the list when it becomes empty. |
125 for (size_t i = 0, size = list->second.size(); i < size; ++i) | 125 for (size_t i = 0, size = list->second.size(); i < size; ++i) |
126 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); | 126 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); |
127 | 127 |
128 CHECK(alarms_.find(extension_id) == alarms_.end()); | 128 CHECK(alarms_.find(extension_id) == alarms_.end()); |
129 WriteToPrefs(extension_id); | 129 WriteToPrefs(extension_id); |
130 } | 130 } |
131 | 131 |
132 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { | 132 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { |
133 // Cancel the timer if there are no more alarms. | |
134 // We don't need to reschedule the poll otherwise, because in | |
135 // the worst case we would just poll one extra time. | |
136 scheduled_times_.erase(iter.second->get()); | |
137 if (scheduled_times_.empty()) | |
138 timer_.Stop(); | |
139 | |
140 // Clean up our alarm list. | |
141 AlarmList& list = iter.first->second; | 133 AlarmList& list = iter.first->second; |
142 list.erase(iter.second); | 134 list.erase(iter.second); |
143 if (list.empty()) | 135 if (list.empty()) |
144 alarms_.erase(iter.first); | 136 alarms_.erase(iter.first); |
| 137 |
| 138 // Cancel the timer if there are no more alarms. |
| 139 // We don't need to reschedule the poll otherwise, because in |
| 140 // the worst case we would just poll one extra time. |
| 141 if (alarms_.empty()) |
| 142 timer_.Stop(); |
145 } | 143 } |
146 | 144 |
147 void AlarmManager::OnAlarm(const std::string& extension_id, | 145 void AlarmManager::OnAlarm(AlarmIterator it) { |
148 const std::string& name) { | |
149 AlarmIterator it = GetAlarmIterator(extension_id, name); | |
150 CHECK(it.first != alarms_.end()); | 146 CHECK(it.first != alarms_.end()); |
151 const Alarm* alarm = it.second->get(); | 147 Alarm& alarm = *it.second; |
152 delegate_->OnAlarm(extension_id, *alarm); | 148 std::string extension_id_copy(it.first->first); |
| 149 delegate_->OnAlarm(extension_id_copy, alarm); |
153 | 150 |
154 std::string extension_id_copy(extension_id); | 151 // Update our scheduled time for the next alarm. |
155 if (!alarm->repeating) { | 152 if (double* period_in_minutes = |
| 153 alarm.js_alarm->period_in_minutes.get()) { |
| 154 alarm.js_alarm->scheduled_time = |
| 155 (last_poll_time_ + |
| 156 TimeDeltaFromDelay(*period_in_minutes)).ToJsTime(); |
| 157 } else { |
156 RemoveAlarmIterator(it); | 158 RemoveAlarmIterator(it); |
157 } else { | |
158 // Update our scheduled time for the next alarm. | |
159 scheduled_times_[alarm].time = | |
160 last_poll_time_ + TimeDeltaFromDelay(alarm->delay_in_minutes); | |
161 } | 159 } |
162 WriteToPrefs(extension_id_copy); | 160 WriteToPrefs(extension_id_copy); |
163 } | 161 } |
164 | 162 |
165 void AlarmManager::AddAlarmImpl(const std::string& extension_id, | 163 void AlarmManager::AddAlarmImpl(const std::string& extension_id, |
166 const linked_ptr<Alarm>& alarm, | 164 const Alarm& alarm) { |
167 base::TimeDelta time_delay) { | |
168 // Override any old alarm with the same name. | 165 // Override any old alarm with the same name. |
169 AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); | 166 AlarmIterator old_alarm = GetAlarmIterator(extension_id, |
| 167 alarm.js_alarm->name); |
170 if (old_alarm.first != alarms_.end()) | 168 if (old_alarm.first != alarms_.end()) |
171 RemoveAlarmIterator(old_alarm); | 169 RemoveAlarmIterator(old_alarm); |
172 | 170 |
173 alarms_[extension_id].push_back(alarm); | 171 alarms_[extension_id].push_back(alarm); |
174 AlarmRuntimeInfo info; | |
175 info.extension_id = extension_id; | |
176 info.time = base::Time::Now() + time_delay; | |
177 scheduled_times_[alarm.get()] = info; | |
178 | 172 |
179 // TODO(yoz): Is 0 really sane? There could be thrashing. | 173 // TODO(yoz): Is 0 really sane? There could be thrashing. |
180 ScheduleNextPoll(base::TimeDelta::FromMinutes(0)); | 174 ScheduleNextPoll(base::TimeDelta::FromMinutes(0)); |
181 } | 175 } |
182 | 176 |
183 void AlarmManager::WriteToPrefs(const std::string& extension_id) { | 177 void AlarmManager::WriteToPrefs(const std::string& extension_id) { |
184 ExtensionService* service = | 178 ExtensionService* service = |
185 ExtensionSystem::Get(profile_)->extension_service(); | 179 ExtensionSystem::Get(profile_)->extension_service(); |
186 if (!service || !service->extension_prefs()) | 180 if (!service || !service->extension_prefs()) |
187 return; | 181 return; |
188 | 182 |
189 std::vector<AlarmPref> alarm_prefs; | |
190 | |
191 AlarmMap::iterator list = alarms_.find(extension_id); | 183 AlarmMap::iterator list = alarms_.find(extension_id); |
192 if (list != alarms_.end()) { | 184 if (list != alarms_.end()) |
193 for (AlarmList::iterator it = list->second.begin(); | 185 service->extension_prefs()->SetRegisteredAlarms( |
194 it != list->second.end(); ++it) { | 186 extension_id, list->second); |
195 AlarmPref pref; | 187 else |
196 pref.alarm = *it; | 188 service->extension_prefs()->SetRegisteredAlarms( |
197 pref.scheduled_run_time = scheduled_times_[it->get()].time; | 189 extension_id, std::vector<Alarm>()); |
198 alarm_prefs.push_back(pref); | |
199 } | |
200 } | |
201 | |
202 service->extension_prefs()->SetRegisteredAlarms(extension_id, alarm_prefs); | |
203 } | 190 } |
204 | 191 |
205 void AlarmManager::ReadFromPrefs(const std::string& extension_id) { | 192 void AlarmManager::ReadFromPrefs(const std::string& extension_id) { |
206 ExtensionService* service = | 193 ExtensionService* service = |
207 ExtensionSystem::Get(profile_)->extension_service(); | 194 ExtensionSystem::Get(profile_)->extension_service(); |
208 if (!service || !service->extension_prefs()) | 195 if (!service || !service->extension_prefs()) |
209 return; | 196 return; |
210 | 197 |
211 std::vector<AlarmPref> alarm_prefs = | 198 std::vector<Alarm> alarm_prefs = |
212 service->extension_prefs()->GetRegisteredAlarms(extension_id); | 199 service->extension_prefs()->GetRegisteredAlarms(extension_id); |
213 for (size_t i = 0; i < alarm_prefs.size(); ++i) { | 200 for (size_t i = 0; i < alarm_prefs.size(); ++i) { |
214 base::TimeDelta delay = | 201 AddAlarmImpl(extension_id, alarm_prefs[i]); |
215 alarm_prefs[i].scheduled_run_time - base::Time::Now(); | |
216 if (delay < base::TimeDelta::FromSeconds(0)) | |
217 delay = base::TimeDelta::FromSeconds(0); | |
218 | |
219 AddAlarmImpl(extension_id, alarm_prefs[i].alarm, delay); | |
220 } | 202 } |
221 } | 203 } |
222 | 204 |
223 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) { | 205 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) { |
224 // 0. If there are no alarms, stop the timer. | 206 // 0. If there are no alarms, stop the timer. |
225 if (scheduled_times_.empty()) { | 207 if (alarms_.empty()) { |
226 timer_.Stop(); | 208 timer_.Stop(); |
227 return; | 209 return; |
228 } | 210 } |
229 | 211 |
230 // TODO(yoz): Try not to reschedule every single time if we're adding | 212 // TODO(yoz): Try not to reschedule every single time if we're adding |
231 // a lot of alarms. | 213 // a lot of alarms. |
232 | 214 |
233 base::Time next_poll(last_poll_time_ + min_period); | 215 base::Time next_poll(last_poll_time_ + min_period); |
234 | 216 |
235 // Find the soonest alarm that is scheduled to run. | 217 // Find the soonest alarm that is scheduled to run. |
236 AlarmRuntimeInfoMap::iterator min_it = scheduled_times_.begin(); | 218 // alarms_ guarantees that none of its contained lists are empty. |
237 for (AlarmRuntimeInfoMap::iterator it = min_it; | 219 base::Time soonest_alarm_time = base::Time::FromJsTime( |
238 it != scheduled_times_.end(); ++it) { | 220 alarms_.begin()->second.begin()->js_alarm->scheduled_time); |
239 if (it->second.time < min_it->second.time) | 221 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end(); |
240 min_it = it; | 222 m_it != m_end; ++m_it) { |
| 223 for (AlarmList::const_iterator l_it = m_it->second.begin(); |
| 224 l_it != m_it->second.end(); ++l_it) { |
| 225 base::Time cur_alarm_time = |
| 226 base::Time::FromJsTime(l_it->js_alarm->scheduled_time); |
| 227 if (cur_alarm_time < soonest_alarm_time) |
| 228 soonest_alarm_time = cur_alarm_time; |
| 229 } |
241 } | 230 } |
242 base::Time soonest_alarm_time(min_it->second.time); | |
243 | 231 |
244 // If the next alarm is more than min_period in the future, wait for it. | 232 // If the next alarm is more than min_period in the future, wait for it. |
245 // Otherwise, only poll as often as min_period. | 233 // Otherwise, only poll as often as min_period. |
246 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) { | 234 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) { |
247 next_poll = soonest_alarm_time; | 235 next_poll = soonest_alarm_time; |
248 } | 236 } |
249 | 237 |
250 // Schedule the poll. | 238 // Schedule the poll. |
251 next_poll_time_ = next_poll; | 239 next_poll_time_ = next_poll; |
252 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0), | 240 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0), |
253 next_poll - base::Time::Now()); | 241 next_poll - now_()); |
254 timer_.Start(FROM_HERE, | 242 timer_.Start(FROM_HERE, |
255 delay, | 243 delay, |
256 this, | 244 this, |
257 &AlarmManager::PollAlarms); | 245 &AlarmManager::PollAlarms); |
258 } | 246 } |
259 | 247 |
260 void AlarmManager::PollAlarms() { | 248 void AlarmManager::PollAlarms() { |
261 last_poll_time_ = base::Time::Now(); | 249 last_poll_time_ = now_(); |
262 | 250 |
263 // Run any alarms scheduled in the past. Note that we could remove alarms | 251 // Run any alarms scheduled in the past. OnAlarm uses vector::erase to remove |
264 // during iteration if they are non-repeating. | 252 // elements from the AlarmList, and map::erase to remove AlarmLists from the |
265 AlarmRuntimeInfoMap::iterator iter = scheduled_times_.begin(); | 253 // AlarmMap. |
266 while (iter != scheduled_times_.end()) { | 254 for (AlarmMap::iterator m_it = alarms_.begin(), m_end = alarms_.end(); |
267 AlarmRuntimeInfoMap::iterator it = iter; | 255 m_it != m_end;) { |
268 ++iter; | 256 AlarmMap::iterator cur_extension = m_it++; |
269 if (it->second.time <= next_poll_time_) { | 257 |
270 OnAlarm(it->second.extension_id, it->first->name); | 258 // Iterate (a) backwards so that removing elements doesn't affect |
| 259 // upcoming iterations, and (b) with indices so that if the last |
| 260 // iteration destroys the AlarmList, I'm not about to use the end |
| 261 // iterator that the destruction invalidates. |
| 262 for (size_t i = cur_extension->second.size(); i > 0; --i) { |
| 263 AlarmList::iterator cur_alarm = cur_extension->second.begin() + i - 1; |
| 264 if (base::Time::FromJsTime(cur_alarm->js_alarm->scheduled_time) <= |
| 265 next_poll_time_) { |
| 266 OnAlarm(make_pair(cur_extension, cur_alarm)); |
| 267 } |
271 } | 268 } |
272 } | 269 } |
273 | 270 |
274 // Schedule the next poll. The soonest it may happen is after | 271 // Schedule the next poll. The soonest it may happen is after |
275 // kDefaultMinPollPeriod or after the shortest scheduled delay of any alarm, | 272 // kDefaultMinPollPeriod or after the shortest granularity of any alarm, |
276 // whichever comes sooner. | 273 // whichever comes sooner. |
277 base::TimeDelta min_poll_period = kDefaultMinPollPeriod; | 274 base::TimeDelta min_poll_period = kDefaultMinPollPeriod; |
278 for (AlarmRuntimeInfoMap::iterator it = scheduled_times_.begin(); | 275 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end(); |
279 it != scheduled_times_.end(); ++it) { | 276 m_it != m_end; ++m_it) { |
280 min_poll_period = std::min(TimeDeltaFromDelay(it->first->delay_in_minutes), | 277 for (AlarmList::const_iterator |
281 min_poll_period); | 278 l_it = m_it->second.begin(), l_end = m_it->second.end(); |
| 279 l_it != l_end; ++l_it) { |
| 280 if (l_it->granularity < min_poll_period) |
| 281 min_poll_period = l_it->granularity; |
| 282 } |
282 } | 283 } |
283 ScheduleNextPoll(min_poll_period); | 284 ScheduleNextPoll(min_poll_period); |
284 } | 285 } |
285 | 286 |
286 void AlarmManager::Observe( | 287 void AlarmManager::Observe( |
287 int type, | 288 int type, |
288 const content::NotificationSource& source, | 289 const content::NotificationSource& source, |
289 const content::NotificationDetails& details) { | 290 const content::NotificationDetails& details) { |
290 switch (type) { | 291 switch (type) { |
291 case chrome::NOTIFICATION_EXTENSION_LOADED: { | 292 case chrome::NOTIFICATION_EXTENSION_LOADED: { |
292 const Extension* extension = | 293 const Extension* extension = |
293 content::Details<const Extension>(details).ptr(); | 294 content::Details<const Extension>(details).ptr(); |
294 ReadFromPrefs(extension->id()); | 295 ReadFromPrefs(extension->id()); |
295 break; | 296 break; |
296 } | 297 } |
297 default: | 298 default: |
298 NOTREACHED(); | 299 NOTREACHED(); |
299 break; | 300 break; |
300 } | 301 } |
301 } | 302 } |
302 | 303 |
303 AlarmPref::AlarmPref() { | 304 // AlarmManager::Alarm |
| 305 |
| 306 Alarm::Alarm() |
| 307 : js_alarm(new api::alarms::Alarm()) { |
304 } | 308 } |
305 | 309 |
306 AlarmPref::~AlarmPref() { | 310 Alarm::Alarm(const std::string& name, |
| 311 const api::alarms::AlarmCreateInfo& create_info, |
| 312 base::TimeDelta min_granularity, |
| 313 TimeProvider now) |
| 314 : js_alarm(new api::alarms::Alarm()) { |
| 315 js_alarm->name = name; |
| 316 |
| 317 if (create_info.when.get()) { |
| 318 // Absolute scheduling. |
| 319 js_alarm->scheduled_time = *create_info.when; |
| 320 granularity = base::Time::FromJsTime(js_alarm->scheduled_time) - now(); |
| 321 } else { |
| 322 // Relative scheduling. |
| 323 double* delay_in_minutes = create_info.delay_in_minutes.get(); |
| 324 if (delay_in_minutes == NULL) |
| 325 delay_in_minutes = create_info.period_in_minutes.get(); |
| 326 CHECK(delay_in_minutes != NULL) |
| 327 << "ValidateAlarmCreateInfo in alarms_api.cc should have " |
| 328 << "prevented this call."; |
| 329 base::TimeDelta delay = TimeDeltaFromDelay(*delay_in_minutes); |
| 330 js_alarm->scheduled_time = (now() + delay).ToJsTime(); |
| 331 granularity = delay; |
| 332 } |
| 333 |
| 334 if (granularity < min_granularity) |
| 335 granularity = min_granularity; |
| 336 |
| 337 // Check for repetition. |
| 338 if (create_info.period_in_minutes.get()) { |
| 339 js_alarm->period_in_minutes.reset( |
| 340 new double(*create_info.period_in_minutes)); |
| 341 } |
| 342 } |
| 343 |
| 344 Alarm::~Alarm() { |
307 } | 345 } |
308 | 346 |
309 } // namespace extensions | 347 } // namespace extensions |
OLD | NEW |