Chromium Code Reviews| 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/themes/theme_service.h" | 5 #include "chrome/browser/themes/theme_service.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/memory/ref_counted_memory.h" | 8 #include "base/memory/ref_counted_memory.h" |
| 9 #include "base/prefs/pref_service.h" | 9 #include "base/prefs/pref_service.h" |
| 10 #include "base/sequenced_task_runner.h" | 10 #include "base/sequenced_task_runner.h" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 48 const char* ThemeService::kDefaultThemeID = ""; | 48 const char* ThemeService::kDefaultThemeID = ""; |
| 49 | 49 |
| 50 namespace { | 50 namespace { |
| 51 | 51 |
| 52 // The default theme if we've gone to the theme gallery and installed the | 52 // The default theme if we've gone to the theme gallery and installed the |
| 53 // "Default" theme. We have to detect this case specifically. (By the time we | 53 // "Default" theme. We have to detect this case specifically. (By the time we |
| 54 // realize we've installed the default theme, we already have an extension | 54 // realize we've installed the default theme, we already have an extension |
| 55 // unpacked on the filesystem.) | 55 // unpacked on the filesystem.) |
| 56 const char* kDefaultThemeGalleryID = "hkacjpbfdknhflllbcmjibkdeoafencn"; | 56 const char* kDefaultThemeGalleryID = "hkacjpbfdknhflllbcmjibkdeoafencn"; |
| 57 | 57 |
| 58 // Wait this many seconds after startup to garbage collect unused themes. | |
|
Yoyo Zhou
2013/07/24 21:55:03
Why wait?
| |
| 59 const int kRemoveUnusedThemesStartupDelay = 30; | |
| 60 | |
| 58 SkColor TintForUnderline(SkColor input) { | 61 SkColor TintForUnderline(SkColor input) { |
| 59 return SkColorSetA(input, SkColorGetA(input) / 3); | 62 return SkColorSetA(input, SkColorGetA(input) / 3); |
| 60 } | 63 } |
| 61 | 64 |
| 62 SkColor IncreaseLightness(SkColor color, double percent) { | 65 SkColor IncreaseLightness(SkColor color, double percent) { |
| 63 color_utils::HSL result; | 66 color_utils::HSL result; |
| 64 color_utils::SkColorToHSL(color, &result); | 67 color_utils::SkColorToHSL(color, &result); |
| 65 result.l += (1 - result.l) * percent; | 68 result.l += (1 - result.l) * percent; |
| 66 return color_utils::HSLToSkColor(result, SkColorGetA(color)); | 69 return color_utils::HSLToSkColor(result, SkColorGetA(color)); |
| 67 } | 70 } |
| 68 | 71 |
| 69 // Writes the theme pack to disk on a separate thread. | 72 // Writes the theme pack to disk on a separate thread. |
| 70 void WritePackToDiskCallback(BrowserThemePack* pack, | 73 void WritePackToDiskCallback(BrowserThemePack* pack, |
| 71 const base::FilePath& path) { | 74 const base::FilePath& path) { |
| 72 if (!pack->WriteToDisk(path)) | 75 if (!pack->WriteToDisk(path)) |
| 73 NOTREACHED() << "Could not write theme pack to disk"; | 76 NOTREACHED() << "Could not write theme pack to disk"; |
| 74 } | 77 } |
| 75 | 78 |
| 76 } // namespace | 79 } // namespace |
| 77 | 80 |
| 78 ThemeService::ThemeService() | 81 ThemeService::ThemeService() |
| 79 : rb_(ResourceBundle::GetSharedInstance()), | 82 : rb_(ResourceBundle::GetSharedInstance()), |
| 80 profile_(NULL), | 83 profile_(NULL), |
| 81 ready_(false), | 84 ready_(false), |
| 82 number_of_infobars_(0) { | 85 number_of_infobars_(0), |
| 86 installed_pending_load_id_(kDefaultThemeID), | |
| 87 weak_ptr_factory_(this) { | |
| 83 } | 88 } |
| 84 | 89 |
| 85 ThemeService::~ThemeService() { | 90 ThemeService::~ThemeService() { |
| 86 FreePlatformCaches(); | 91 FreePlatformCaches(); |
| 87 } | 92 } |
| 88 | 93 |
| 89 void ThemeService::Init(Profile* profile) { | 94 void ThemeService::Init(Profile* profile) { |
| 90 DCHECK(CalledOnValidThread()); | 95 DCHECK(CalledOnValidThread()); |
| 91 profile_ = profile; | 96 profile_ = profile; |
| 92 | 97 |
| 93 LoadThemePrefs(); | 98 LoadThemePrefs(); |
| 94 | 99 |
| 95 if (!ready_) { | 100 if (!ready_) { |
| 96 registrar_.Add(this, | 101 registrar_.Add(this, |
| 97 chrome::NOTIFICATION_EXTENSIONS_READY, | 102 chrome::NOTIFICATION_EXTENSIONS_READY, |
| 98 content::Source<Profile>(profile_)); | 103 content::Source<Profile>(profile_)); |
| 99 } | 104 } |
| 100 | 105 |
| 101 theme_syncable_service_.reset(new ThemeSyncableService(profile_, this)); | 106 theme_syncable_service_.reset(new ThemeSyncableService(profile_, this)); |
| 107 | |
| 108 registrar_.Add(this, | |
| 109 chrome::NOTIFICATION_EXTENSION_INSTALLED, | |
| 110 content::Source<Profile>(profile_)); | |
| 111 registrar_.Add(this, | |
| 112 chrome::NOTIFICATION_EXTENSION_LOADED, | |
| 113 content::Source<Profile>(profile_)); | |
| 114 registrar_.Add(this, | |
| 115 chrome::NOTIFICATION_EXTENSION_ENABLED, | |
| 116 content::Source<Profile>(profile_)); | |
| 117 registrar_.Add(this, | |
| 118 chrome::NOTIFICATION_EXTENSION_UNLOADED, | |
| 119 content::Source<Profile>(profile_)); | |
| 120 | |
| 121 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
| 122 base::Bind(&ThemeService::RemoveUnusedThemes, | |
| 123 weak_ptr_factory_.GetWeakPtr(), | |
| 124 false), | |
| 125 base::TimeDelta::FromSeconds(kRemoveUnusedThemesStartupDelay)); | |
| 102 } | 126 } |
| 103 | 127 |
| 104 gfx::Image ThemeService::GetImageNamed(int id) const { | 128 gfx::Image ThemeService::GetImageNamed(int id) const { |
| 105 DCHECK(CalledOnValidThread()); | 129 DCHECK(CalledOnValidThread()); |
| 106 | 130 |
| 107 // For a managed user, use the special frame instead of the default one. | 131 // For a managed user, use the special frame instead of the default one. |
| 108 // TODO(akuegel): Remove this once we have the default managed user theme. | 132 // TODO(akuegel): Remove this once we have the default managed user theme. |
| 109 if (IsManagedUser()) { | 133 if (IsManagedUser()) { |
| 110 if (id == IDR_THEME_FRAME) | 134 if (id == IDR_THEME_FRAME) |
| 111 id = IDR_MANAGED_USER_THEME_FRAME; | 135 id = IDR_MANAGED_USER_THEME_FRAME; |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 data = theme_pack_->GetRawData(id, scale_factor); | 246 data = theme_pack_->GetRawData(id, scale_factor); |
| 223 if (!data) | 247 if (!data) |
| 224 data = rb_.LoadDataResourceBytesForScale(id, ui::SCALE_FACTOR_100P); | 248 data = rb_.LoadDataResourceBytesForScale(id, ui::SCALE_FACTOR_100P); |
| 225 | 249 |
| 226 return data; | 250 return data; |
| 227 } | 251 } |
| 228 | 252 |
| 229 void ThemeService::Observe(int type, | 253 void ThemeService::Observe(int type, |
| 230 const content::NotificationSource& source, | 254 const content::NotificationSource& source, |
| 231 const content::NotificationDetails& details) { | 255 const content::NotificationDetails& details) { |
| 232 DCHECK(type == chrome::NOTIFICATION_EXTENSIONS_READY); | 256 using content::Details; |
| 233 registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY, | 257 switch (type) { |
| 234 content::Source<Profile>(profile_)); | 258 case chrome::NOTIFICATION_EXTENSIONS_READY: |
| 259 registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY, | |
| 260 content::Source<Profile>(profile_)); | |
| 235 | 261 |
| 236 MigrateTheme(); | 262 MigrateTheme(); |
| 237 set_ready(); | 263 set_ready(); |
| 238 | 264 |
| 239 // Send notification in case anyone requested data and cached it when the | 265 // Send notification in case anyone requested data and cached it when the |
| 240 // theme service was not ready yet. | 266 // theme service was not ready yet. |
| 241 NotifyThemeChanged(); | 267 NotifyThemeChanged(); |
| 268 break; | |
| 269 case chrome::NOTIFICATION_EXTENSION_INSTALLED: | |
| 270 { | |
| 271 Details<const extensions::InstalledExtensionInfo> installed_details( | |
| 272 details); | |
| 273 // 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
| |
| 274 // to change the current theme. | |
| 275 if (installed_details->extension->is_theme()) | |
| 276 installed_pending_load_id_ = installed_details->extension->id(); | |
| 277 break; | |
| 278 } | |
| 279 case chrome::NOTIFICATION_EXTENSION_LOADED: | |
| 280 { | |
| 281 const Extension* extension = Details<const Extension>(details).ptr(); | |
| 282 if (extension->is_theme() && | |
| 283 installed_pending_load_id_ != kDefaultThemeID && | |
| 284 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'
| |
| 285 SetTheme(extension); | |
| 286 } | |
| 287 installed_pending_load_id_ = kDefaultThemeID; | |
| 288 } | |
| 289 case chrome::NOTIFICATION_EXTENSION_ENABLED: | |
| 290 { | |
| 291 const Extension* extension = Details<const Extension>(details).ptr(); | |
| 292 if (extension->is_theme()) | |
| 293 SetTheme(extension); | |
| 294 break; | |
| 295 } | |
| 296 case chrome::NOTIFICATION_EXTENSION_UNLOADED: | |
| 297 { | |
| 298 Details<const extensions::UnloadedExtensionInfo> unloaded_details( | |
| 299 details); | |
| 300 if (unloaded_details->reason != extension_misc::UNLOAD_REASON_UPDATE && | |
| 301 unloaded_details->extension->is_theme() && | |
| 302 unloaded_details->extension->id() == GetThemeID()) { | |
| 303 UseDefaultTheme(); | |
| 304 } | |
| 305 break; | |
| 306 } | |
| 307 } | |
| 242 } | 308 } |
| 243 | 309 |
| 244 void ThemeService::SetTheme(const Extension* extension) { | 310 void ThemeService::SetTheme(const Extension* extension) { |
| 311 DCHECK(extension->is_theme()); | |
| 312 ExtensionService* service = | |
| 313 extensions::ExtensionSystem::Get(profile_)->extension_service(); | |
| 314 if (!service->IsExtensionEnabled(extension->id())) { | |
| 315 // |extension| is disabled when reverting to the previous theme via an | |
| 316 // infobar. | |
| 317 service->EnableExtension(extension->id()); | |
| 318 // Enabling the extension will call back to SetTheme(). | |
| 319 return; | |
| 320 } | |
| 321 | |
| 322 std::string previous_theme_id = GetThemeID(); | |
| 323 | |
| 245 // Clear our image cache. | 324 // Clear our image cache. |
| 246 FreePlatformCaches(); | 325 FreePlatformCaches(); |
| 247 | 326 |
| 248 DCHECK(extension); | |
| 249 DCHECK(extension->is_theme()); | |
| 250 if (DCHECK_IS_ON()) { | |
| 251 ExtensionService* service = | |
| 252 extensions::ExtensionSystem::Get(profile_)->extension_service(); | |
| 253 DCHECK(service); | |
| 254 DCHECK(service->GetExtensionById(extension->id(), false)); | |
| 255 } | |
| 256 | |
| 257 BuildFromExtension(extension); | 327 BuildFromExtension(extension); |
| 258 SaveThemeID(extension->id()); | 328 SaveThemeID(extension->id()); |
| 259 | 329 |
| 260 NotifyThemeChanged(); | 330 NotifyThemeChanged(); |
| 261 content::RecordAction(UserMetricsAction("Themes_Installed")); | 331 content::RecordAction(UserMetricsAction("Themes_Installed")); |
| 332 | |
| 333 if (previous_theme_id != kDefaultThemeID && | |
| 334 previous_theme_id != extension->id()) { | |
| 335 // Disable the old theme. | |
| 336 service->DisableExtension(previous_theme_id, | |
| 337 extensions::Extension::DISABLE_USER_ACTION); | |
| 338 } | |
| 262 } | 339 } |
| 263 | 340 |
| 264 void ThemeService::RemoveUnusedThemes() { | 341 void ThemeService::RemoveUnusedThemes(bool ignore_infobars) { |
| 342 if (!ignore_infobars && number_of_infobars_ != 0) | |
| 343 return; | |
| 265 if (!profile_) | 344 if (!profile_) |
| 266 return; | 345 return; |
| 267 ExtensionService* service = profile_->GetExtensionService(); | 346 ExtensionService* service = profile_->GetExtensionService(); |
| 268 if (!service) | 347 if (!service) |
| 269 return; | 348 return; |
| 270 std::string current_theme = GetThemeID(); | 349 std::string current_theme = GetThemeID(); |
| 271 std::vector<std::string> remove_list; | 350 std::vector<std::string> remove_list; |
| 272 const ExtensionSet* extensions = service->extensions(); | 351 const ExtensionSet* extensions = service->extensions(); |
| 273 for (ExtensionSet::const_iterator it = extensions->begin(); | 352 for (ExtensionSet::const_iterator it = extensions->begin(); |
| 274 it != extensions->end(); ++it) { | 353 it != extensions->end(); ++it) { |
| 275 if ((*it)->is_theme() && (*it)->id() != current_theme) { | 354 if ((*it)->is_theme() && (*it)->id() != current_theme) { |
| 276 remove_list.push_back((*it)->id()); | 355 remove_list.push_back((*it)->id()); |
| 277 } | 356 } |
| 278 } | 357 } |
| 358 extensions = service->disabled_extensions(); | |
| 359 for (ExtensionSet::const_iterator it = extensions->begin(); | |
| 360 it != extensions->end(); ++it) { | |
| 361 if ((*it)->is_theme() && (*it)->id() != current_theme) { | |
| 362 remove_list.push_back((*it)->id()); | |
| 363 } | |
| 364 } | |
| 279 for (size_t i = 0; i < remove_list.size(); ++i) | 365 for (size_t i = 0; i < remove_list.size(); ++i) |
| 280 service->UninstallExtension(remove_list[i], false, NULL); | 366 service->UninstallExtension(remove_list[i], false, NULL); |
| 281 } | 367 } |
| 282 | 368 |
| 283 void ThemeService::UseDefaultTheme() { | 369 void ThemeService::UseDefaultTheme() { |
| 284 ClearAllThemeData(); | 370 ClearAllThemeData(); |
| 285 NotifyThemeChanged(); | 371 NotifyThemeChanged(); |
| 286 content::RecordAction(UserMetricsAction("Themes_Reset")); | 372 content::RecordAction(UserMetricsAction("Themes_Reset")); |
| 287 } | 373 } |
| 288 | 374 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 315 } | 401 } |
| 316 | 402 |
| 317 void ThemeService::ClearAllThemeData() { | 403 void ThemeService::ClearAllThemeData() { |
| 318 // Clear our image cache. | 404 // Clear our image cache. |
| 319 FreePlatformCaches(); | 405 FreePlatformCaches(); |
| 320 theme_pack_ = NULL; | 406 theme_pack_ = NULL; |
| 321 | 407 |
| 322 profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename); | 408 profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename); |
| 323 SaveThemeID(kDefaultThemeID); | 409 SaveThemeID(kDefaultThemeID); |
| 324 | 410 |
| 325 RemoveUnusedThemes(); | 411 // There should be no more infobars. This may not be the case because of |
| 412 // http://crbug.com/62154 | |
| 413 base::MessageLoop::current()->PostTask(FROM_HERE, | |
| 414 base::Bind(&ThemeService::RemoveUnusedThemes, | |
| 415 weak_ptr_factory_.GetWeakPtr(), | |
| 416 true)); | |
| 326 } | 417 } |
| 327 | 418 |
| 328 void ThemeService::LoadThemePrefs() { | 419 void ThemeService::LoadThemePrefs() { |
| 329 PrefService* prefs = profile_->GetPrefs(); | 420 PrefService* prefs = profile_->GetPrefs(); |
| 330 | 421 |
| 331 std::string current_id = GetThemeID(); | 422 std::string current_id = GetThemeID(); |
| 332 if (current_id == kDefaultThemeID) { | 423 if (current_id == kDefaultThemeID) { |
| 333 set_ready(); | 424 set_ready(); |
| 334 return; | 425 return; |
| 335 } | 426 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 } | 532 } |
| 442 | 533 |
| 443 void ThemeService::OnInfobarDisplayed() { | 534 void ThemeService::OnInfobarDisplayed() { |
| 444 number_of_infobars_++; | 535 number_of_infobars_++; |
| 445 } | 536 } |
| 446 | 537 |
| 447 void ThemeService::OnInfobarDestroyed() { | 538 void ThemeService::OnInfobarDestroyed() { |
| 448 number_of_infobars_--; | 539 number_of_infobars_--; |
| 449 | 540 |
| 450 if (number_of_infobars_ == 0) | 541 if (number_of_infobars_ == 0) |
| 451 RemoveUnusedThemes(); | 542 RemoveUnusedThemes(false); |
| 452 } | 543 } |
| 453 | 544 |
| 454 ThemeSyncableService* ThemeService::GetThemeSyncableService() const { | 545 ThemeSyncableService* ThemeService::GetThemeSyncableService() const { |
| 455 return theme_syncable_service_.get(); | 546 return theme_syncable_service_.get(); |
| 456 } | 547 } |
| OLD | NEW |