Chromium Code Reviews| Index: chrome/browser/themes/theme_service.cc |
| diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc |
| index d7fe33bd290520c6da71f222a288f2fe1bd3adbf..e6e3bbd26fb9ba79c589382c0347424d0dcdee52 100644 |
| --- a/chrome/browser/themes/theme_service.cc |
| +++ b/chrome/browser/themes/theme_service.cc |
| @@ -55,6 +55,9 @@ namespace { |
| // unpacked on the filesystem.) |
| const char* kDefaultThemeGalleryID = "hkacjpbfdknhflllbcmjibkdeoafencn"; |
| +// Wait this many seconds after startup to garbage collect unused themes. |
|
Yoyo Zhou
2013/07/24 21:55:03
Why wait?
|
| +const int kRemoveUnusedThemesStartupDelay = 30; |
| + |
| SkColor TintForUnderline(SkColor input) { |
| return SkColorSetA(input, SkColorGetA(input) / 3); |
| } |
| @@ -79,7 +82,9 @@ ThemeService::ThemeService() |
| : rb_(ResourceBundle::GetSharedInstance()), |
| profile_(NULL), |
| ready_(false), |
| - number_of_infobars_(0) { |
| + number_of_infobars_(0), |
| + installed_pending_load_id_(kDefaultThemeID), |
| + weak_ptr_factory_(this) { |
| } |
| ThemeService::~ThemeService() { |
| @@ -99,6 +104,25 @@ void ThemeService::Init(Profile* profile) { |
| } |
| theme_syncable_service_.reset(new ThemeSyncableService(profile_, this)); |
| + |
| + registrar_.Add(this, |
| + chrome::NOTIFICATION_EXTENSION_INSTALLED, |
| + content::Source<Profile>(profile_)); |
| + registrar_.Add(this, |
| + chrome::NOTIFICATION_EXTENSION_LOADED, |
| + content::Source<Profile>(profile_)); |
| + registrar_.Add(this, |
| + chrome::NOTIFICATION_EXTENSION_ENABLED, |
| + content::Source<Profile>(profile_)); |
| + registrar_.Add(this, |
| + chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| + content::Source<Profile>(profile_)); |
| + |
| + base::MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| + base::Bind(&ThemeService::RemoveUnusedThemes, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + false), |
| + base::TimeDelta::FromSeconds(kRemoveUnusedThemesStartupDelay)); |
| } |
| gfx::Image ThemeService::GetImageNamed(int id) const { |
| @@ -229,39 +253,94 @@ base::RefCountedMemory* ThemeService::GetRawData( |
| void ThemeService::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| - DCHECK(type == chrome::NOTIFICATION_EXTENSIONS_READY); |
| - registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
| - content::Source<Profile>(profile_)); |
| + using content::Details; |
| + switch (type) { |
| + case chrome::NOTIFICATION_EXTENSIONS_READY: |
| + registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
| + content::Source<Profile>(profile_)); |
| - MigrateTheme(); |
| - set_ready(); |
| + MigrateTheme(); |
| + set_ready(); |
| - // Send notification in case anyone requested data and cached it when the |
| - // theme service was not ready yet. |
| - NotifyThemeChanged(); |
| + // Send notification in case anyone requested data and cached it when the |
| + // theme service was not ready yet. |
| + NotifyThemeChanged(); |
| + break; |
| + case chrome::NOTIFICATION_EXTENSION_INSTALLED: |
| + { |
| + Details<const extensions::InstalledExtensionInfo> installed_details( |
| + details); |
| + // The theme may be initially disabled. Wait till it is loaded (if ever) |
|
Yoyo Zhou
2013/07/24 21:55:03
I don't see why we need to listen for extension in
pkotwicz
2013/07/25 01:25:29
You are right. I should be able to move registerin
|
| + // to change the current theme. |
| + if (installed_details->extension->is_theme()) |
| + installed_pending_load_id_ = installed_details->extension->id(); |
| + break; |
| + } |
| + case chrome::NOTIFICATION_EXTENSION_LOADED: |
| + { |
| + const Extension* extension = Details<const Extension>(details).ptr(); |
| + if (extension->is_theme() && |
| + installed_pending_load_id_ != kDefaultThemeID && |
| + installed_pending_load_id_ == extension->id()) { |
|
Yoyo Zhou
2013/07/24 21:55:03
What's the scenario where we load a theme and don'
|
| + SetTheme(extension); |
| + } |
| + installed_pending_load_id_ = kDefaultThemeID; |
| + } |
| + case chrome::NOTIFICATION_EXTENSION_ENABLED: |
| + { |
| + const Extension* extension = Details<const Extension>(details).ptr(); |
| + if (extension->is_theme()) |
| + SetTheme(extension); |
| + break; |
| + } |
| + case chrome::NOTIFICATION_EXTENSION_UNLOADED: |
| + { |
| + Details<const extensions::UnloadedExtensionInfo> unloaded_details( |
| + details); |
| + if (unloaded_details->reason != extension_misc::UNLOAD_REASON_UPDATE && |
| + unloaded_details->extension->is_theme() && |
| + unloaded_details->extension->id() == GetThemeID()) { |
| + UseDefaultTheme(); |
| + } |
| + break; |
| + } |
| + } |
| } |
| void ThemeService::SetTheme(const Extension* extension) { |
| - // Clear our image cache. |
| - FreePlatformCaches(); |
| - |
| - DCHECK(extension); |
| DCHECK(extension->is_theme()); |
| - if (DCHECK_IS_ON()) { |
| - ExtensionService* service = |
| - extensions::ExtensionSystem::Get(profile_)->extension_service(); |
| - DCHECK(service); |
| - DCHECK(service->GetExtensionById(extension->id(), false)); |
| + ExtensionService* service = |
| + extensions::ExtensionSystem::Get(profile_)->extension_service(); |
| + if (!service->IsExtensionEnabled(extension->id())) { |
| + // |extension| is disabled when reverting to the previous theme via an |
| + // infobar. |
| + service->EnableExtension(extension->id()); |
| + // Enabling the extension will call back to SetTheme(). |
| + return; |
| } |
| + std::string previous_theme_id = GetThemeID(); |
| + |
| + // Clear our image cache. |
| + FreePlatformCaches(); |
| + |
| BuildFromExtension(extension); |
| SaveThemeID(extension->id()); |
| NotifyThemeChanged(); |
| content::RecordAction(UserMetricsAction("Themes_Installed")); |
| + |
| + if (previous_theme_id != kDefaultThemeID && |
| + previous_theme_id != extension->id()) { |
| + // Disable the old theme. |
| + service->DisableExtension(previous_theme_id, |
| + extensions::Extension::DISABLE_USER_ACTION); |
| + } |
| } |
| -void ThemeService::RemoveUnusedThemes() { |
| +void ThemeService::RemoveUnusedThemes(bool ignore_infobars) { |
| + if (!ignore_infobars && number_of_infobars_ != 0) |
| + return; |
| if (!profile_) |
| return; |
| ExtensionService* service = profile_->GetExtensionService(); |
| @@ -276,6 +355,13 @@ void ThemeService::RemoveUnusedThemes() { |
| remove_list.push_back((*it)->id()); |
| } |
| } |
| + extensions = service->disabled_extensions(); |
| + for (ExtensionSet::const_iterator it = extensions->begin(); |
| + it != extensions->end(); ++it) { |
| + if ((*it)->is_theme() && (*it)->id() != current_theme) { |
| + remove_list.push_back((*it)->id()); |
| + } |
| + } |
| for (size_t i = 0; i < remove_list.size(); ++i) |
| service->UninstallExtension(remove_list[i], false, NULL); |
| } |
| @@ -322,7 +408,12 @@ void ThemeService::ClearAllThemeData() { |
| profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename); |
| SaveThemeID(kDefaultThemeID); |
| - RemoveUnusedThemes(); |
| + // There should be no more infobars. This may not be the case because of |
| + // http://crbug.com/62154 |
| + base::MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(&ThemeService::RemoveUnusedThemes, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + true)); |
| } |
| void ThemeService::LoadThemePrefs() { |
| @@ -448,7 +539,7 @@ void ThemeService::OnInfobarDestroyed() { |
| number_of_infobars_--; |
| if (number_of_infobars_ == 0) |
| - RemoveUnusedThemes(); |
| + RemoveUnusedThemes(false); |
| } |
| ThemeSyncableService* ThemeService::GetThemeSyncableService() const { |