Index: chrome/browser/extensions/api/alarms/alarm_manager.cc |
diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.cc b/chrome/browser/extensions/api/alarms/alarm_manager.cc |
index 17a48898c3b2317fc039120069fcbe6af7426cbb..b7621048cce45429a1762b122b18050585b9a0e2 100644 |
--- a/chrome/browser/extensions/api/alarms/alarm_manager.cc |
+++ b/chrome/browser/extensions/api/alarms/alarm_manager.cc |
@@ -9,8 +9,12 @@ |
#include "base/message_loop.h" |
#include "base/values.h" |
#include "chrome/browser/extensions/extension_event_router.h" |
+#include "chrome/browser/extensions/extension_prefs.h" |
+#include "chrome/browser/extensions/extension_service.h" |
#include "chrome/browser/extensions/extension_system.h" |
#include "chrome/browser/profiles/profile.h" |
+#include "chrome/common/chrome_notification_types.h" |
+#include "content/public/browser/notification_service.h" |
namespace extensions { |
@@ -39,9 +43,22 @@ class DefaultAlarmDelegate : public AlarmManager::Delegate { |
} |
+struct AlarmManager::TimerInfo { |
+ base::Timer timer; |
+ base::Time scheduled_run_time; |
Aaron Boodman
2012/04/20 17:58:22
I don't understand why you introduced this struct.
Matt Perry
2012/04/20 19:38:49
It's used when persisting to prefs. Each time we p
Aaron Boodman
2012/04/20 23:15:24
I see.
|
+ |
+ explicit TimerInfo(bool repeating) : timer(true, repeating) {} |
+ |
+ void UpdateScheduledRunTime() { |
+ scheduled_run_time = base::Time::Now() + timer.GetCurrentDelay(); |
+ } |
+}; |
+ |
AlarmManager::AlarmManager(Profile* profile) |
: profile_(profile), |
delegate_(new DefaultAlarmDelegate(profile)) { |
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
+ content::Source<Profile>(profile_)); |
} |
AlarmManager::~AlarmManager() { |
@@ -49,21 +66,9 @@ AlarmManager::~AlarmManager() { |
void AlarmManager::AddAlarm(const std::string& extension_id, |
const linked_ptr<Alarm>& alarm) { |
- // TODO(mpcomplete): Better handling of granularity. |
- // http://crbug.com/122683 |
- |
- // Override any old alarm with the same name. |
- AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); |
- if (old_alarm.first != alarms_.end()) |
- RemoveAlarmIterator(old_alarm); |
- |
- alarms_[extension_id].push_back(alarm); |
- base::Timer* timer = new base::Timer(true, alarm->repeating); |
- timers_[alarm.get()] = make_linked_ptr(timer); |
- timer->Start(FROM_HERE, |
- base::TimeDelta::FromSeconds(alarm->delay_in_seconds), |
- base::Bind(&AlarmManager::OnAlarm, base::Unretained(this), |
- extension_id, alarm->name)); |
+ AddAlarmImpl(extension_id, alarm, |
+ base::TimeDelta::FromSeconds(alarm->delay_in_seconds)); |
+ WriteToPrefs(extension_id); |
} |
const AlarmManager::Alarm* AlarmManager::GetAlarm( |
@@ -102,7 +107,9 @@ bool AlarmManager::RemoveAlarm(const std::string& extension_id, |
AlarmIterator it = GetAlarmIterator(extension_id, name); |
if (it.first == alarms_.end()) |
return false; |
+ |
RemoveAlarmIterator(it); |
+ WriteToPrefs(extension_id); |
return true; |
} |
@@ -117,11 +124,12 @@ void AlarmManager::RemoveAllAlarms(const std::string& extension_id) { |
RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); |
CHECK(alarms_.find(extension_id) == alarms_.end()); |
+ WriteToPrefs(extension_id); |
} |
void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { |
// Cancel the timer first. |
- timers_[iter.second->get()]->Stop(); |
+ timers_[iter.second->get()]->timer.Stop(); |
timers_.erase(iter.second->get()); |
// Clean up our alarm list. |
@@ -135,10 +143,105 @@ void AlarmManager::OnAlarm(const std::string& extension_id, |
const std::string& name) { |
AlarmIterator it = GetAlarmIterator(extension_id, name); |
CHECK(it.first != alarms_.end()); |
- delegate_->OnAlarm(extension_id, *it.second->get()); |
+ const Alarm* alarm = it.second->get(); |
+ delegate_->OnAlarm(extension_id, *alarm); |
- if (!(*it.second)->repeating) |
+ if (!alarm->repeating) { |
RemoveAlarmIterator(it); |
+ } else { |
+ // Restart the timer, since it may have been set with a shorter delay. |
+ TimerInfo* timer = timers_[alarm].get(); |
+ timer->timer.Start(FROM_HERE, |
+ base::TimeDelta::FromSeconds(alarm->delay_in_seconds), |
+ base::Bind(&AlarmManager::OnAlarm, base::Unretained(this), |
+ extension_id, alarm->name)); |
+ timer->UpdateScheduledRunTime(); |
+ } |
+ |
+ WriteToPrefs(extension_id); |
+} |
+ |
+void AlarmManager::AddAlarmImpl(const std::string& extension_id, |
+ const linked_ptr<Alarm>& alarm, |
+ base::TimeDelta timer_delay) { |
+ // Override any old alarm with the same name. |
+ AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); |
+ if (old_alarm.first != alarms_.end()) |
+ RemoveAlarmIterator(old_alarm); |
+ |
+ alarms_[extension_id].push_back(alarm); |
+ |
+ TimerInfo* timer = new TimerInfo(alarm->repeating); |
Aaron Boodman
2012/04/20 17:58:22
Nit: Maybe name this timer_info so you don't have
|
+ timers_[alarm.get()] = make_linked_ptr(timer); |
+ timer->timer.Start(FROM_HERE, |
+ timer_delay, |
+ base::Bind(&AlarmManager::OnAlarm, base::Unretained(this), |
+ extension_id, alarm->name)); |
+ timer->UpdateScheduledRunTime(); |
+} |
+ |
+void AlarmManager::WriteToPrefs(const std::string& extension_id) { |
+ ExtensionService* service = |
+ ExtensionSystem::Get(profile_)->extension_service(); |
Aaron Boodman
2012/04/20 17:58:22
Consider passing in ExtensionPrefs to make this mo
Matt Perry
2012/04/20 19:38:49
I don't think that's necessary. TestExtensionSyste
Aaron Boodman
2012/04/20 23:15:24
It's not necessary, but it seems nice to keep the
Matt Perry
2012/04/20 23:39:42
Yeah, I see what you're saying, but I'm not a fan
Aaron Boodman
2012/04/20 23:50:12
That is really odd to me. Creating a mock profile
|
+ if (!service || !service->extension_prefs()) |
+ return; |
+ |
+ std::vector<AlarmPref> alarm_prefs; |
+ |
+ AlarmMap::iterator list = alarms_.find(extension_id); |
Aaron Boodman
2012/04/20 17:58:22
This reminds me: We should limit extensions to som
Matt Perry
2012/04/20 19:38:49
Are you worried about malicious extensions carpet-
Aaron Boodman
2012/04/20 23:15:24
I'm was thinking about buggy extensions filling up
Matt Perry
2012/04/20 23:39:42
They would each have to have a different name. I s
Aaron Boodman
2012/04/20 23:50:12
Hm, ok. Let's talk about this more next week. Diff
|
+ if (list != alarms_.end()) { |
+ for (AlarmList::iterator it = list->second.begin(); |
+ it != list->second.end(); ++it) { |
+ TimerInfo* timer = timers_[it->get()].get(); |
+ AlarmPref pref; |
+ pref.alarm = *it; |
+ pref.scheduled_run_time = timer->scheduled_run_time; |
+ alarm_prefs.push_back(pref); |
+ } |
+ } |
+ |
+ service->extension_prefs()->SetRegisteredAlarms(extension_id, alarm_prefs); |
+} |
+ |
+void AlarmManager::ReadFromPrefs(const std::string& extension_id) { |
+ ExtensionService* service = |
+ ExtensionSystem::Get(profile_)->extension_service(); |
+ if (!service || !service->extension_prefs()) |
+ return; |
+ |
+ std::vector<AlarmPref> alarm_prefs = |
+ service->extension_prefs()->GetRegisteredAlarms(extension_id); |
+ for (size_t i = 0; i < alarm_prefs.size(); ++i) { |
+ base::TimeDelta delay = |
+ alarm_prefs[i].scheduled_run_time - base::Time::Now(); |
+ if (delay < base::TimeDelta::FromSeconds(0)) |
+ delay = base::TimeDelta::FromSeconds(0); |
+ |
+ AddAlarmImpl(extension_id, alarm_prefs[i].alarm, delay); |
+ } |
+} |
+ |
+void AlarmManager::Observe( |
+ int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) { |
+ switch (type) { |
+ case chrome::NOTIFICATION_EXTENSION_LOADED: { |
+ const Extension* extension = |
+ content::Details<const Extension>(details).ptr(); |
+ ReadFromPrefs(extension->id()); |
+ break; |
+ } |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+} |
+ |
+AlarmPref::AlarmPref() { |
+} |
+ |
+AlarmPref::~AlarmPref() { |
} |
} // namespace extensions |