15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/themes/theme_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted_memory.h"
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/message_loop/message_loop.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/sequenced_task_runner.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
172385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/managed_mode/managed_user_theme.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/themes/browser_theme_pack.h"
20558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/browser/themes/custom_theme_supplier.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/themes/theme_properties.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/themes/theme_syncable_service.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/layout.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/win/shell.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::UserMetricsAction;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using extensions::UnloadedExtensionInfo;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ui::ResourceBundle;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef ThemeProperties Properties;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The default theme if we haven't installed a theme yet or if we've clicked
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the "Use Classic" button.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* ThemeService::kDefaultThemeID = "";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The default theme if we've gone to the theme gallery and installed the
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "Default" theme. We have to detect this case specifically. (By the time we
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// realize we've installed the default theme, we already have an extension
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// unpacked on the filesystem.)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* kDefaultThemeGalleryID = "hkacjpbfdknhflllbcmjibkdeoafencn";
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Wait this many seconds after startup to garbage collect unused themes.
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Removing unused themes is done after a delay because there is no
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// reason to do it at startup.
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// ExtensionService::GarbageCollectExtensions() does something similar.
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int kRemoveUnusedThemesStartupDelay = 30;
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor IncreaseLightness(SkColor color, double percent) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  color_utils::HSL result;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  color_utils::SkColorToHSL(color, &result);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result.l += (1 - result.l) * percent;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return color_utils::HSLToSkColor(result, SkColorGetA(color));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Writes the theme pack to disk on a separate thread.
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WritePackToDiskCallback(BrowserThemePack* pack,
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const base::FilePath& path) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pack->WriteToDisk(path))
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Could not write theme pack to disk";
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThemeService::ThemeService()
80bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    : ready_(false),
81bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      rb_(ResourceBundle::GetSharedInstance()),
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(NULL),
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      installed_pending_load_id_(kDefaultThemeID),
84ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      number_of_infobars_(0),
85ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      weak_ptr_factory_(this) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThemeService::~ThemeService() {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreePlatformCaches();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::Init(Profile* profile) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_ = profile;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadThemePrefs();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  registrar_.Add(this,
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 chrome::NOTIFICATION_EXTENSIONS_READY,
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 content::Source<Profile>(profile_));
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  theme_syncable_service_.reset(new ThemeSyncableService(profile_, this));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Image ThemeService::GetImageNamed(int id) const {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::Image image;
109558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (theme_supplier_.get())
110558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    image = theme_supplier_->GetImageNamed(id);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (image.IsEmpty())
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    image = rb_.GetNativeImageNamed(id);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return image;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia* ThemeService::GetImageSkiaNamed(int id) const {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Image image = GetImageNamed(id);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image.IsEmpty())
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): Remove this const cast.  The gfx::Image interface returns
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // its images const. GetImageSkiaNamed() also should but has many callsites.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return const_cast<gfx::ImageSkia*>(image.ToImageSkia());
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor ThemeService::GetColor(int id) const {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkColor color;
130558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (theme_supplier_.get() && theme_supplier_->GetColor(id, &color))
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return color;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For backward compat with older themes, some newer colors are generated from
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // older ones if they are missing.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (id) {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Properties::COLOR_NTP_SECTION_HEADER_TEXT:
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT), 0.30);
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Properties::COLOR_NTP_SECTION_HEADER_TEXT_HOVER:
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return GetColor(Properties::COLOR_NTP_TEXT);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Properties::COLOR_NTP_SECTION_HEADER_RULE:
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT), 0.70);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Properties::COLOR_NTP_SECTION_HEADER_RULE_LIGHT:
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT), 0.86);
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Properties::COLOR_NTP_TEXT_LIGHT:
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT), 0.40);
1467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case Properties::COLOR_MANAGED_USER_LABEL:
147558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return color_utils::GetReadableColor(
148558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          SK_ColorWHITE,
149558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          GetColor(Properties::COLOR_MANAGED_USER_LABEL_BACKGROUND));
1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case Properties::COLOR_MANAGED_USER_LABEL_BACKGROUND:
151558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return color_utils::BlendTowardOppositeLuminance(
152558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          GetColor(Properties::COLOR_FRAME), 0x80);
153ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case Properties::COLOR_MANAGED_USER_LABEL_BORDER:
154ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return color_utils::AlphaBlend(
155ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          GetColor(Properties::COLOR_MANAGED_USER_LABEL_BACKGROUND),
156ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          SK_ColorBLACK,
157ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          230);
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case Properties::COLOR_STATUS_BAR_TEXT: {
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // A long time ago, we blended the toolbar and the tab text together to
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // get the status bar text because, at the time, our text rendering in
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // views couldn't do alpha blending. Even though this is no longer the
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // case, this blending decision is built into the majority of themes that
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // exist, and we must keep doing it.
164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      SkColor toolbar_color = GetColor(Properties::COLOR_TOOLBAR);
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      SkColor text_color = GetColor(Properties::COLOR_TAB_TEXT);
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return SkColorSetARGB(
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          SkColorGetA(text_color),
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          (SkColorGetR(text_color) + SkColorGetR(toolbar_color)) / 2,
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          (SkColorGetG(text_color) + SkColorGetR(toolbar_color)) / 2,
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          (SkColorGetB(text_color) + SkColorGetR(toolbar_color)) / 2);
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Properties::GetDefaultColor(id);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
177424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)int ThemeService::GetDisplayProperty(int id) const {
178424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int result = 0;
179424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (theme_supplier_.get() &&
180424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      theme_supplier_->GetDisplayProperty(id, &result)) {
181424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return result;
182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (id == Properties::NTP_LOGO_ALTERNATE &&
185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      !UsingDefaultTheme() &&
186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      !UsingNativeTheme()) {
187424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Use the alternate logo for themes from the web store except for
188424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // |kDefaultThemeGalleryID|.
189424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return 1;
190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return Properties::GetDefaultDisplayProperty(id);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThemeService::ShouldUseNativeFrame() const {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasCustomImage(IDR_THEME_FRAME))
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::win::IsAeroGlassEnabled();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThemeService::HasCustomImage(int id) const {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!Properties::IsThemeableImage(id))
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
209558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (theme_supplier_.get())
210558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return theme_supplier_->HasCustomImage(id);
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::RefCountedMemory* ThemeService::GetRawData(
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::ScaleFactor scale_factor) const {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check to see whether we should substitute some images.
219424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int ntp_alternate = GetDisplayProperty(Properties::NTP_LOGO_ALTERNATE);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id == IDR_PRODUCT_LOGO && ntp_alternate != 0)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    id = IDR_PRODUCT_LOGO_WHITE;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::RefCountedMemory* data = NULL;
224558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (theme_supplier_.get())
225558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    data = theme_supplier_->GetRawData(id, scale_factor);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!data)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data = rb_.LoadDataResourceBytesForScale(id, ui::SCALE_FACTOR_100P);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return data;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ThemeService::Observe(int type,
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           const content::NotificationSource& source,
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           const content::NotificationDetails& details) {
2353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  using content::Details;
2363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  switch (type) {
2373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSIONS_READY:
2383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          content::Source<Profile>(profile_));
2403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      OnExtensionServiceReady();
2413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
2423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
2433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    {
2443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // The theme may be initially disabled. Wait till it is loaded (if ever).
2453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Details<const extensions::InstalledExtensionInfo> installed_details(
2463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          details);
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (installed_details->extension->is_theme())
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        installed_pending_load_id_ = installed_details->extension->id();
2493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
2503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_LOADED:
2523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    {
2533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      const Extension* extension = Details<const Extension>(details).ptr();
2543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (extension->is_theme() &&
2553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          installed_pending_load_id_ != kDefaultThemeID &&
2563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          installed_pending_load_id_ == extension->id()) {
2573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        SetTheme(extension);
2583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
2593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      installed_pending_load_id_ = kDefaultThemeID;
2603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_ENABLED:
2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    {
2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      const Extension* extension = Details<const Extension>(details).ptr();
2653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (extension->is_theme())
2663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        SetTheme(extension);
2673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
2683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
2703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    {
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      Details<const UnloadedExtensionInfo> unloaded_details(details);
2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      if (unloaded_details->reason != UnloadedExtensionInfo::REASON_UPDATE &&
2733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          unloaded_details->extension->is_theme() &&
2743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          unloaded_details->extension->id() == GetThemeID()) {
2753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        UseDefaultTheme();
2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
2773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
2783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
280bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
282bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid ThemeService::SetTheme(const Extension* extension) {
283bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  DCHECK(extension->is_theme());
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ExtensionService* service =
2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->extension_service();
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!service->IsExtensionEnabled(extension->id())) {
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // |extension| is disabled when reverting to the previous theme via an
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // infobar.
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    service->EnableExtension(extension->id());
2903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Enabling the extension will call back to SetTheme().
2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
292bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
293bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string previous_theme_id = GetThemeID();
2953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Clear our image cache.
2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FreePlatformCaches();
2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BuildFromExtension(extension);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveThemeID(extension->id());
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyThemeChanged();
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::RecordAction(UserMetricsAction("Themes_Installed"));
3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (previous_theme_id != kDefaultThemeID &&
3063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      previous_theme_id != extension->id()) {
3073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Disable the old theme.
3083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    service->DisableExtension(previous_theme_id,
3093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                              extensions::Extension::DISABLE_USER_ACTION);
3103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
313558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid ThemeService::SetCustomDefaultTheme(
314558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    scoped_refptr<CustomThemeSupplier> theme_supplier) {
315558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  ClearAllThemeData();
316558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  SwapThemeSupplier(theme_supplier);
317558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  NotifyThemeChanged();
318558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
319558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
320558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool ThemeService::ShouldInitWithNativeTheme() const {
321558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return false;
322558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
323558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
3243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ThemeService::RemoveUnusedThemes(bool ignore_infobars) {
325558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // We do not want to garbage collect themes on startup (|ready_| is false).
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Themes will get garbage collected after |kRemoveUnusedThemesStartupDelay|.
327558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!profile_ || !ready_)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ignore_infobars && number_of_infobars_ != 0)
3303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
331558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionService* service = profile_->GetExtensionService();
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!service)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string current_theme = GetThemeID();
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> remove_list;
3373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_ptr<const ExtensionSet> extensions(
3383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      service->GenerateInstalledExtensionsSet());
3393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  extensions::ExtensionPrefs* prefs = service->extension_prefs();
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ExtensionSet::const_iterator it = extensions->begin();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != extensions->end(); ++it) {
3423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const extensions::Extension* extension = *it;
3433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (extension->is_theme() &&
3443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        extension->id() != current_theme) {
3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // Only uninstall themes which are not disabled or are disabled with
3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // reason DISABLE_USER_ACTION. We cannot blanket uninstall all disabled
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // themes because externally installed themes are initially disabled.
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      int disable_reason = prefs->GetDisableReasons(extension->id());
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (!prefs->IsExtensionDisabled(extension->id()) ||
3503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          disable_reason == Extension::DISABLE_USER_ACTION) {
3513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        remove_list.push_back((*it)->id());
3523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO: Garbage collect all unused themes. This method misses themes which
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // are installed but not loaded because they are blacklisted by a management
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // policy provider.
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < remove_list.size(); ++i)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service->UninstallExtension(remove_list[i], false, NULL);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::UseDefaultTheme() {
364558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (ready_)
365558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    content::RecordAction(UserMetricsAction("Themes_Reset"));
366558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (IsManagedUser()) {
367558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    SetManagedUserTheme();
368558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return;
369558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
370bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ClearAllThemeData();
371bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  NotifyThemeChanged();
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::SetNativeTheme() {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UseDefaultTheme();
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThemeService::UsingDefaultTheme() const {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string id = GetThemeID();
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return id == ThemeService::kDefaultThemeID ||
381424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      id == kDefaultThemeGalleryID;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThemeService::UsingNativeTheme() const {
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return UsingDefaultTheme();
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string ThemeService::GetThemeID() const {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return profile_->GetPrefs()->GetString(prefs::kCurrentThemeID);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)color_utils::HSL ThemeService::GetTint(int id) const {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  color_utils::HSL hsl;
396558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (theme_supplier_.get() && theme_supplier_->GetTint(id, &hsl))
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hsl;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ThemeProperties::GetDefaultTint(id);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::ClearAllThemeData() {
403bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (!ready_)
404bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return;
405bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
406558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  SwapThemeSupplier(NULL);
407558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear our image cache.
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreePlatformCaches();
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveThemeID(kDefaultThemeID);
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // There should be no more infobars. This may not be the case because of
4153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // http://crbug.com/62154
4163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // RemoveUnusedThemes is called on a task because ClearAllThemeData() may
4173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // be called as a result of NOTIFICATION_EXTENSION_UNLOADED.
4183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::MessageLoop::current()->PostTask(FROM_HERE,
4193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&ThemeService::RemoveUnusedThemes,
4203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
4213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 true));
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::LoadThemePrefs() {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* prefs = profile_->GetPrefs();
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string current_id = GetThemeID();
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_id == kDefaultThemeID) {
429558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // Managed users have a different default theme.
430558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (IsManagedUser())
431558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      SetManagedUserTheme();
432558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    else if (ShouldInitWithNativeTheme())
433558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      SetNativeTheme();
434558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    else
435558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      UseDefaultTheme();
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    set_ready();
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool loaded_pack = false;
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If we don't have a file pack, we're updating from an old version.
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path = prefs->GetFilePath(prefs::kCurrentThemePackFilename);
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (path != base::FilePath()) {
445558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    SwapThemeSupplier(BrowserThemePack::BuildFromDataPack(path, current_id));
446558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    loaded_pack = theme_supplier_.get() != NULL;
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (loaded_pack) {
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::RecordAction(UserMetricsAction("Themes.Loaded"));
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    set_ready();
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Else: wait for the extension service to be ready so that the theme pack
4543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // can be recreated from the extension.
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::NotifyThemeChanged() {
458558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!ready_)
459558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return;
460558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Sending BROWSER_THEME_CHANGED";
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Redraw!
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationService* service =
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NotificationService::current();
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service->Notify(chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  content::Source<ThemeService>(this),
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  content::NotificationService::NoDetails());
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyPlatformThemeChanged();
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_MACOSX
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify sync that theme has changed.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (theme_syncable_service_.get()) {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    theme_syncable_service_->OnThemeChange();
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) || defined(USE_AURA)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::FreePlatformCaches() {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Views (Skia) has no platform image cache to clear.
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ThemeService::OnExtensionServiceReady() {
4853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ready_) {
4863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // If the ThemeService is not ready yet, the custom theme data pack needs to
4873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // be recreated from the extension.
4883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    MigrateTheme();
4893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    set_ready();
4903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Send notification in case anyone requested data and cached it when the
4923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // theme service was not ready yet.
4933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NotifyThemeChanged();
4943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  registrar_.Add(this,
4973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 chrome::NOTIFICATION_EXTENSION_INSTALLED,
4983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 content::Source<Profile>(profile_));
4993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  registrar_.Add(this,
5003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 chrome::NOTIFICATION_EXTENSION_LOADED,
5013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 content::Source<Profile>(profile_));
5023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  registrar_.Add(this,
5033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 chrome::NOTIFICATION_EXTENSION_ENABLED,
5043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 content::Source<Profile>(profile_));
5053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  registrar_.Add(this,
5063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 chrome::NOTIFICATION_EXTENSION_UNLOADED,
5073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 content::Source<Profile>(profile_));
5083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
5103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&ThemeService::RemoveUnusedThemes,
5113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
5123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 false),
5133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::TimeDelta::FromSeconds(kRemoveUnusedThemesStartupDelay));
514558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
515558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ThemeService::MigrateTheme() {
5173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(erg): We need to pop up a dialog informing the user that their
5183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // theme is being migrated.
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* service =
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->extension_service();
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Extension* extension = service ?
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      service->GetExtensionById(GetThemeID(), false) : NULL;
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extension) {
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DLOG(ERROR) << "Migrating theme";
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BuildFromExtension(extension);
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::RecordAction(UserMetricsAction("Themes.Migrated"));
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DLOG(ERROR) << "Theme is mysteriously gone.";
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ClearAllThemeData();
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::RecordAction(UserMetricsAction("Themes.Gone"));
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ThemeService::SwapThemeSupplier(
5353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    scoped_refptr<CustomThemeSupplier> theme_supplier) {
5363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (theme_supplier_.get())
5373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    theme_supplier_->StopUsingTheme();
5383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  theme_supplier_ = theme_supplier;
5393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (theme_supplier_.get())
5403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    theme_supplier_->StartUsingTheme();
5413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ThemeService::SavePackName(const base::FilePath& pack_path) {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_->GetPrefs()->SetFilePath(
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      prefs::kCurrentThemePackFilename, pack_path);
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::SaveThemeID(const std::string& id) {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, id);
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::BuildFromExtension(const Extension* extension) {
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<BrowserThemePack> pack(
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThemePack::BuildFromExtension(extension));
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pack.get()) {
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(erg): We've failed to install the theme; perhaps we should tell the
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // user? http://crbug.com/34780
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Could not load theme.";
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* service =
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->extension_service();
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!service)
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write the packed file to disk.
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath pack_path =
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension->path().Append(chrome::kThemePackFilename);
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service->GetFileTaskRunner()->PostTask(
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&WritePackToDiskCallback, pack, pack_path));
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SavePackName(pack_path);
575558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  SwapThemeSupplier(pack);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
578eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ThemeService::IsManagedUser() const {
579a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return profile_->IsManaged();
580eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
581eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
582558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid ThemeService::SetManagedUserTheme() {
583558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  SetCustomDefaultTheme(new ManagedUserTheme);
584558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
585558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::OnInfobarDisplayed() {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  number_of_infobars_++;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThemeService::OnInfobarDestroyed() {
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  number_of_infobars_--;
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (number_of_infobars_ == 0)
5943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    RemoveUnusedThemes(false);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThemeSyncableService* ThemeService::GetThemeSyncableService() const {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return theme_syncable_service_.get();
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
600