diff options
-rw-r--r-- | base/timer.h | 1 | ||||
-rw-r--r-- | chrome/browser/extensions/api/alarms/alarm_manager.cc | 127 | ||||
-rw-r--r-- | chrome/browser/extensions/api/alarms/alarm_manager.h | 28 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_prefs.cc | 45 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_prefs.h | 11 |
5 files changed, 193 insertions, 19 deletions
diff --git a/base/timer.h b/base/timer.h index 24f2bb1..faa12da 100644 --- a/base/timer.h +++ b/base/timer.h @@ -108,6 +108,7 @@ class BASE_EXPORT Timer { void Reset(); const base::Closure& user_task() const { return user_task_; } + const TimeTicks& desired_run_time() const { return desired_run_time_; } protected: // Used to initiate a new delayed task. This has the side-effect of disabling diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.cc b/chrome/browser/extensions/api/alarms/alarm_manager.cc index 17a4889..f6c5080 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 { @@ -42,6 +46,8 @@ class DefaultAlarmDelegate : public AlarmManager::Delegate { 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 +55,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 +96,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,6 +113,7 @@ 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) { @@ -135,10 +132,106 @@ 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 + // initially. + base::Timer* timer = timers_[alarm].get(); + timer->Start(FROM_HERE, + base::TimeDelta::FromSeconds(alarm->delay_in_seconds), + base::Bind(&AlarmManager::OnAlarm, base::Unretained(this), + extension_id, alarm->name)); + } + + 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); + + base::Timer* timer = new base::Timer(true, alarm->repeating); + timers_[alarm.get()] = make_linked_ptr(timer); + timer->Start(FROM_HERE, + timer_delay, + base::Bind(&AlarmManager::OnAlarm, base::Unretained(this), + extension_id, alarm->name)); +} + +void AlarmManager::WriteToPrefs(const std::string& extension_id) { + ExtensionService* service = + ExtensionSystem::Get(profile_)->extension_service(); + if (!service || !service->extension_prefs()) + return; + + std::vector<AlarmPref> alarm_prefs; + + AlarmMap::iterator list = alarms_.find(extension_id); + if (list != alarms_.end()) { + for (AlarmList::iterator it = list->second.begin(); + it != list->second.end(); ++it) { + base::Timer* timer = timers_[it->get()].get(); + base::TimeDelta delay = + timer->desired_run_time() - base::TimeTicks::Now(); + AlarmPref pref; + pref.alarm = *it; + pref.scheduled_run_time = base::Time::Now() + delay; + 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 diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.h b/chrome/browser/extensions/api/alarms/alarm_manager.h index 775fd1e..6ca8dc07 100644 --- a/chrome/browser/extensions/api/alarms/alarm_manager.h +++ b/chrome/browser/extensions/api/alarms/alarm_manager.h @@ -13,6 +13,8 @@ #include "base/timer.h" #include "chrome/browser/extensions/extension_function.h" #include "chrome/common/extensions/api/experimental.alarms.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" class Profile; @@ -20,7 +22,7 @@ namespace extensions { // Manages the currently pending alarms for every extension in a profile. // There is one manager per virtual Profile. -class AlarmManager { +class AlarmManager : public content::NotificationObserver { public: typedef extensions::api::experimental_alarms::Alarm Alarm; typedef std::vector<linked_ptr<Alarm> > AlarmList; @@ -79,7 +81,22 @@ class AlarmManager { // Callback for when an alarm fires. void OnAlarm(const std::string& extension_id, const std::string& name); + // Internal helper to add an alarm and start the timer with the given delay. + void AddAlarmImpl(const std::string& extension_id, + const linked_ptr<Alarm>& alarm, + base::TimeDelta timer_delay); + + // Syncs our alarm data for the given extension to/from the prefs file. + void WriteToPrefs(const std::string& extension_id); + void ReadFromPrefs(const std::string& extension_id); + + // NotificationObserver: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + Profile* profile_; + content::NotificationRegistrar registrar_; scoped_ptr<Delegate> delegate_; // A map of our pending alarms, per extension. @@ -89,6 +106,15 @@ class AlarmManager { std::map<const Alarm*, linked_ptr<base::Timer> > timers_; }; +// Contains the data we store in the extension prefs for each alarm. +struct AlarmPref { + linked_ptr<AlarmManager::Alarm> alarm; + base::Time scheduled_run_time; + + AlarmPref(); + ~AlarmPref(); +}; + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARM_MANAGER_H__ diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index 7dc67c8..793a04e 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -7,6 +7,7 @@ #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/extensions/api/alarms/alarm_manager.h" #include "chrome/browser/extensions/extension_pref_store.h" #include "chrome/browser/extensions/extension_sorting.h" #include "chrome/browser/prefs/pref_notifier.h" @@ -156,6 +157,10 @@ const char kPrefIncognitoContentSettings[] = "incognito_content_settings"; // background page. const char kRegisteredEvents[] = "events"; +// A list of alarms that this extension has set. +const char kRegisteredAlarms[] = "alarms"; +const char kAlarmScheduledRunTime[] = "scheduled_run_time"; + // Provider of write access to a dictionary storing extension prefs. class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate { public: @@ -933,6 +938,43 @@ void ExtensionPrefs::SetRegisteredEvents( UpdateExtensionPref(extension_id, kRegisteredEvents, value); } +std::vector<extensions::AlarmPref> ExtensionPrefs::GetRegisteredAlarms( + const std::string& extension_id) { + std::vector<extensions::AlarmPref> alarms; + const base::DictionaryValue* extension = GetExtensionPref(extension_id); + if (!extension) + return alarms; + + base::ListValue* list = NULL; + if (!extension->GetList(kRegisteredAlarms, &list)) + return alarms; + + typedef extensions::AlarmManager::Alarm Alarm; + for (size_t i = 0; i < list->GetSize(); ++i) { + base::DictionaryValue* alarm_dict = NULL; + extensions::AlarmPref alarm; + alarm.alarm.reset(new Alarm()); + if (list->GetDictionary(i, &alarm_dict) && + Alarm::Populate(*alarm_dict, alarm.alarm.get())) { + alarm.scheduled_run_time = ReadTime(alarm_dict, kAlarmScheduledRunTime); + alarms.push_back(alarm); + } + } + return alarms; +} + +void ExtensionPrefs::SetRegisteredAlarms( + const std::string& extension_id, + const std::vector<extensions::AlarmPref>& alarms) { + base::ListValue* list = new ListValue(); + for (size_t i = 0; i < alarms.size(); ++i) { + scoped_ptr<base::DictionaryValue> alarm = alarms[i].alarm->ToValue().Pass(); + SaveTime(alarm.get(), kAlarmScheduledRunTime, alarms[i].scheduled_run_time); + list->Append(alarm.release()); + } + UpdateExtensionPref(extension_id, kRegisteredAlarms, list); +} + bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) { return ReadExtensionPrefBoolean(extension_id, kPrefIncognitoEnabled); } @@ -1130,8 +1172,9 @@ void ExtensionPrefs::OnExtensionInstalled( extension->manifest()->value()->DeepCopy()); } - // Clear any events that may be registered from a previous install. + // Clear any events and alarms that may be registered from a previous install. extension_dict->Remove(kRegisteredEvents, NULL); + extension_dict->Remove(kRegisteredAlarms, NULL); if (extension->is_app()) { StringOrdinal new_page_ordinal = page_ordinal.IsValid() ? diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h index ddebe41..c3791f9 100644 --- a/chrome/browser/extensions/extension_prefs.h +++ b/chrome/browser/extensions/extension_prefs.h @@ -24,6 +24,10 @@ class ExtensionSorting; class PrefService; class URLPatternSet; +namespace extensions { +struct AlarmPref; +} + // Class for managing global and per-extension preferences. // // This class distinguishes the following kinds of preferences: @@ -260,6 +264,13 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer, void SetRegisteredEvents(const std::string& extension_id, const std::set<std::string>& events); + // Controls a list of alarms for this extension, including the next time they + // should run. + std::vector<extensions::AlarmPref> GetRegisteredAlarms( + const std::string& extension_id); + void SetRegisteredAlarms(const std::string& extension_id, + const std::vector<extensions::AlarmPref>& alarms); + // Returns true if the user enabled this extension to be loaded in incognito // mode. bool IsIncognitoEnabled(const std::string& extension_id); |