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 |