Merge from Chromium at DEPS revision r215573
This commit was generated by merge_to_master.py.
Change-Id: Ib95814f98e5765b459dd32425f9bf9138edf2bca
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 22e9e28..08595e7 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
@@ -34,7 +35,6 @@
#endif
#if defined(ENABLE_MANAGED_USERS)
-#include "chrome/browser/managed_mode/managed_user_service.h"
#include "chrome/browser/managed_mode/managed_user_theme.h"
#endif
@@ -57,6 +57,12 @@
// unpacked on the filesystem.)
const char* kDefaultThemeGalleryID = "hkacjpbfdknhflllbcmjibkdeoafencn";
+// Wait this many seconds after startup to garbage collect unused themes.
+// Removing unused themes is done after a delay because there is no
+// reason to do it at startup.
+// ExtensionService::GarbageCollectExtensions() does something similar.
+const int kRemoveUnusedThemesStartupDelay = 30;
+
SkColor TintForUnderline(SkColor input) {
return SkColorSetA(input, SkColorGetA(input) / 3);
}
@@ -81,7 +87,9 @@
: rb_(ResourceBundle::GetSharedInstance()),
profile_(NULL),
ready_(false),
- number_of_infobars_(0) {
+ installed_pending_load_id_(kDefaultThemeID),
+ number_of_infobars_(0),
+ weak_ptr_factory_(this) {
}
ThemeService::~ThemeService() {
@@ -94,11 +102,9 @@
LoadThemePrefs();
- if (!ready_) {
- registrar_.Add(this,
- chrome::NOTIFICATION_EXTENSIONS_READY,
- content::Source<Profile>(profile_));
- }
+ registrar_.Add(this,
+ chrome::NOTIFICATION_EXTENSIONS_READY,
+ content::Source<Profile>(profile_));
theme_syncable_service_.reset(new ThemeSyncableService(profile_, this));
}
@@ -204,36 +210,83 @@
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_));
-
- MigrateTheme();
- set_ready();
-
- // Send notification in case anyone requested data and cached it when the
- // theme service was not ready yet.
- NotifyThemeChanged();
+ using content::Details;
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSIONS_READY:
+ registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
+ content::Source<Profile>(profile_));
+ OnExtensionServiceReady();
+ break;
+ case chrome::NOTIFICATION_EXTENSION_INSTALLED:
+ {
+ // The theme may be initially disabled. Wait till it is loaded (if ever).
+ Details<const extensions::InstalledExtensionInfo> installed_details(
+ details);
+ 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()) {
+ SetTheme(extension);
+ }
+ installed_pending_load_id_ = kDefaultThemeID;
+ break;
+ }
+ 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) {
+ DCHECK(extension->is_theme());
+ 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();
- 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));
- }
-
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::SetCustomDefaultTheme(
@@ -247,25 +300,41 @@
return false;
}
-void ThemeService::RemoveUnusedThemes() {
+void ThemeService::RemoveUnusedThemes(bool ignore_infobars) {
// We do not want to garbage collect themes on startup (|ready_| is false).
- // Themes will get garbage collected once
- // ExtensionService::GarbageCollectExtensions() runs.
+ // Themes will get garbage collected after |kRemoveUnusedThemesStartupDelay|.
if (!profile_ || !ready_)
return;
+ if (!ignore_infobars && number_of_infobars_ != 0)
+ return;
ExtensionService* service = profile_->GetExtensionService();
if (!service)
return;
std::string current_theme = GetThemeID();
std::vector<std::string> remove_list;
- const ExtensionSet* extensions = service->extensions();
+ scoped_ptr<const ExtensionSet> extensions(
+ service->GenerateInstalledExtensionsSet());
+ extensions::ExtensionPrefs* prefs = service->extension_prefs();
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());
+ const extensions::Extension* extension = *it;
+ if (extension->is_theme() &&
+ extension->id() != current_theme) {
+ // Only uninstall themes which are not disabled or are disabled with
+ // reason DISABLE_USER_ACTION. We cannot blanket uninstall all disabled
+ // themes because externally installed themes are initially disabled.
+ int disable_reason = prefs->GetDisableReasons(extension->id());
+ if (!prefs->IsExtensionDisabled(extension->id()) ||
+ disable_reason == Extension::DISABLE_USER_ACTION) {
+ remove_list.push_back((*it)->id());
+ }
}
}
+ // TODO: Garbage collect all unused themes. This method misses themes which
+ // are installed but not loaded because they are blacklisted by a management
+ // policy provider.
+
for (size_t i = 0; i < remove_list.size(); ++i)
service->UninstallExtension(remove_list[i], false, NULL);
}
@@ -320,7 +389,14 @@
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
+ // RemoveUnusedThemes is called on a task because ClearAllThemeData() may
+ // be called as a result of NOTIFICATION_EXTENSION_UNLOADED.
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&ThemeService::RemoveUnusedThemes,
+ weak_ptr_factory_.GetWeakPtr(),
+ true));
}
void ThemeService::LoadThemePrefs() {
@@ -351,16 +427,9 @@
if (loaded_pack) {
content::RecordAction(UserMetricsAction("Themes.Loaded"));
set_ready();
- } else {
- // TODO(erg): We need to pop up a dialog informing the user that their
- // theme is being migrated.
- ExtensionService* service =
- extensions::ExtensionSystem::Get(profile_)->extension_service();
- if (service && service->is_ready()) {
- MigrateTheme();
- set_ready();
- }
}
+ // Else: wait for the extension service to be ready so that the theme pack
+ // can be recreated from the extension.
}
void ThemeService::NotifyThemeChanged() {
@@ -390,16 +459,41 @@
}
#endif
-void ThemeService::SwapThemeSupplier(
- scoped_refptr<CustomThemeSupplier> theme_supplier) {
- if (theme_supplier_.get())
- theme_supplier_->StopUsingTheme();
- theme_supplier_ = theme_supplier;
- if (theme_supplier_.get())
- theme_supplier_->StartUsingTheme();
+void ThemeService::OnExtensionServiceReady() {
+ if (!ready_) {
+ // If the ThemeService is not ready yet, the custom theme data pack needs to
+ // be recreated from the extension.
+ MigrateTheme();
+ set_ready();
+
+ // Send notification in case anyone requested data and cached it when the
+ // theme service was not ready yet.
+ NotifyThemeChanged();
+ }
+
+ 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));
}
void ThemeService::MigrateTheme() {
+ // TODO(erg): We need to pop up a dialog informing the user that their
+ // theme is being migrated.
ExtensionService* service =
extensions::ExtensionSystem::Get(profile_)->extension_service();
const Extension* extension = service ?
@@ -415,6 +509,15 @@
}
}
+void ThemeService::SwapThemeSupplier(
+ scoped_refptr<CustomThemeSupplier> theme_supplier) {
+ if (theme_supplier_.get())
+ theme_supplier_->StopUsingTheme();
+ theme_supplier_ = theme_supplier;
+ if (theme_supplier_.get())
+ theme_supplier_->StartUsingTheme();
+}
+
void ThemeService::SavePackName(const base::FilePath& pack_path) {
profile_->GetPrefs()->SetFilePath(
prefs::kCurrentThemePackFilename, pack_path);
@@ -451,15 +554,14 @@
}
bool ThemeService::IsManagedUser() const {
-#if defined(ENABLE_MANAGED_USERS)
- return ManagedUserService::ProfileIsManaged(profile_);
-#endif
- return false;
+ return profile_->IsManaged();
}
void ThemeService::SetManagedUserTheme() {
#if defined(ENABLE_MANAGED_USERS)
SetCustomDefaultTheme(new ManagedUserTheme);
+#else
+ NOTREACHED();
#endif
}
@@ -471,7 +573,7 @@
number_of_infobars_--;
if (number_of_infobars_ == 0)
- RemoveUnusedThemes();
+ RemoveUnusedThemes(false);
}
ThemeSyncableService* ThemeService::GetThemeSyncableService() const {