• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/sync/glue/theme_util.h"
6 
7 #include <string>
8 
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "chrome/browser/extensions/extension_install_ui.h"
12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/extension_updater.h"
14 #if defined(TOOLKIT_USES_GTK)
15 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
16 #endif
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/sync/protocol/theme_specifics.pb.h"
19 #include "chrome/browser/themes/theme_service.h"
20 #include "chrome/browser/themes/theme_service_factory.h"
21 #include "chrome/common/extensions/extension.h"
22 #include "chrome/common/extensions/extension_constants.h"
23 #include "googleurl/src/gurl.h"
24 
25 namespace browser_sync {
26 
27 const char kCurrentThemeClientTag[] = "current_theme";
28 
29 namespace {
30 
IsSystemThemeDistinctFromDefaultTheme()31 bool IsSystemThemeDistinctFromDefaultTheme() {
32 #if defined(TOOLKIT_USES_GTK)
33   return true;
34 #else
35   return false;
36 #endif
37 }
38 
UseSystemTheme(Profile * profile)39 bool UseSystemTheme(Profile* profile) {
40 #if defined(TOOLKIT_USES_GTK)
41   return GtkThemeService::GetFrom(profile)->UseGtkTheme();
42 #else
43   return false;
44 #endif
45 }
46 
47 }  // namespace
48 
AreThemeSpecificsEqual(const sync_pb::ThemeSpecifics & a,const sync_pb::ThemeSpecifics & b)49 bool AreThemeSpecificsEqual(const sync_pb::ThemeSpecifics& a,
50                             const sync_pb::ThemeSpecifics& b) {
51   return AreThemeSpecificsEqualHelper(
52       a, b, IsSystemThemeDistinctFromDefaultTheme());
53 }
54 
AreThemeSpecificsEqualHelper(const sync_pb::ThemeSpecifics & a,const sync_pb::ThemeSpecifics & b,bool is_system_theme_distinct_from_default_theme)55 bool AreThemeSpecificsEqualHelper(
56     const sync_pb::ThemeSpecifics& a,
57     const sync_pb::ThemeSpecifics& b,
58     bool is_system_theme_distinct_from_default_theme) {
59   if (a.use_custom_theme() != b.use_custom_theme()) {
60     return false;
61   }
62 
63   if (a.use_custom_theme()) {
64     // We're using a custom theme, so simply compare IDs since those
65     // are guaranteed unique.
66     return a.custom_theme_id() == b.custom_theme_id();
67   } else if (is_system_theme_distinct_from_default_theme) {
68     // We're not using a custom theme, but we care about system
69     // vs. default.
70     return a.use_system_theme_by_default() == b.use_system_theme_by_default();
71   } else {
72     // We're not using a custom theme, and we don't care about system
73     // vs. default.
74     return true;
75   }
76 }
77 
78 namespace {
79 
IsTheme(const Extension & extension)80 bool IsTheme(const Extension& extension) {
81   return extension.is_theme();
82 }
83 
84 }  // namespace
85 
SetCurrentThemeFromThemeSpecifics(const sync_pb::ThemeSpecifics & theme_specifics,Profile * profile)86 void SetCurrentThemeFromThemeSpecifics(
87     const sync_pb::ThemeSpecifics& theme_specifics,
88     Profile* profile) {
89   DCHECK(profile);
90   if (theme_specifics.use_custom_theme()) {
91     // TODO(akalin): Figure out what to do about third-party themes
92     // (i.e., those not on either Google gallery).
93     std::string id(theme_specifics.custom_theme_id());
94     GURL update_url(theme_specifics.custom_theme_update_url());
95     VLOG(1) << "Applying theme " << id << " with update_url " << update_url;
96     ExtensionServiceInterface* extensions_service =
97         profile->GetExtensionService();
98     CHECK(extensions_service);
99     const Extension* extension = extensions_service->GetExtensionById(id, true);
100     if (extension) {
101       if (!extension->is_theme()) {
102         VLOG(1) << "Extension " << id << " is not a theme; aborting";
103         return;
104       }
105       if (!extensions_service->IsExtensionEnabled(id)) {
106         VLOG(1) << "Theme " << id << " is not enabled; aborting";
107         return;
108       }
109       // Get previous theme info before we set the new theme.
110       std::string previous_theme_id;
111       {
112         const Extension* current_theme =
113             ThemeServiceFactory::GetThemeForProfile(profile);
114         if (current_theme) {
115           DCHECK(current_theme->is_theme());
116           previous_theme_id = current_theme->id();
117         }
118       }
119       bool previous_use_system_theme = UseSystemTheme(profile);
120       // An enabled theme extension with the given id was found, so
121       // just set the current theme to it.
122       ThemeServiceFactory::GetForProfile(profile)->SetTheme(extension);
123       // Pretend the theme was just installed.
124       ExtensionInstallUI::ShowThemeInfoBar(
125           previous_theme_id, previous_use_system_theme,
126           extension, profile);
127     } else {
128       // No extension with this id exists -- we must install it; we do
129       // so by adding it as a pending extension and then triggering an
130       // auto-update cycle.
131       // Themes don't need to install silently as they just pop up an
132       // informational dialog after installation instead of a
133       // confirmation dialog.
134       const bool kInstallSilently = false;
135       const bool kEnableOnInstall = true;
136       const bool kEnableIncognitoOnInstall = false;
137       extensions_service->pending_extension_manager()->AddFromSync(
138           id, update_url, &IsTheme,
139           kInstallSilently, kEnableOnInstall, kEnableIncognitoOnInstall);
140       extensions_service->CheckForUpdatesSoon();
141     }
142   } else if (theme_specifics.use_system_theme_by_default()) {
143     ThemeServiceFactory::GetForProfile(profile)->SetNativeTheme();
144   } else {
145     ThemeServiceFactory::GetForProfile(profile)->UseDefaultTheme();
146   }
147 }
148 
UpdateThemeSpecificsOrSetCurrentThemeIfNecessary(Profile * profile,sync_pb::ThemeSpecifics * theme_specifics)149 bool UpdateThemeSpecificsOrSetCurrentThemeIfNecessary(
150     Profile* profile, sync_pb::ThemeSpecifics* theme_specifics) {
151   if (!theme_specifics->use_custom_theme() &&
152       (ThemeServiceFactory::GetThemeForProfile(profile) ||
153        (UseSystemTheme(profile) &&
154         IsSystemThemeDistinctFromDefaultTheme()))) {
155     GetThemeSpecificsFromCurrentTheme(profile, theme_specifics);
156     return true;
157   } else {
158     SetCurrentThemeFromThemeSpecificsIfNecessary(*theme_specifics, profile);
159     return false;
160   }
161 }
162 
GetThemeSpecificsFromCurrentTheme(Profile * profile,sync_pb::ThemeSpecifics * theme_specifics)163 void GetThemeSpecificsFromCurrentTheme(
164     Profile* profile,
165     sync_pb::ThemeSpecifics* theme_specifics) {
166   DCHECK(profile);
167   const Extension* current_theme =
168       ThemeServiceFactory::GetThemeForProfile(profile);
169   if (current_theme) {
170     DCHECK(current_theme->is_theme());
171   }
172   GetThemeSpecificsFromCurrentThemeHelper(
173       current_theme,
174       IsSystemThemeDistinctFromDefaultTheme(),
175       UseSystemTheme(profile),
176       theme_specifics);
177 }
178 
GetThemeSpecificsFromCurrentThemeHelper(const Extension * current_theme,bool is_system_theme_distinct_from_default_theme,bool use_system_theme_by_default,sync_pb::ThemeSpecifics * theme_specifics)179 void GetThemeSpecificsFromCurrentThemeHelper(
180     const Extension* current_theme,
181     bool is_system_theme_distinct_from_default_theme,
182     bool use_system_theme_by_default,
183     sync_pb::ThemeSpecifics* theme_specifics) {
184   bool use_custom_theme = (current_theme != NULL);
185   theme_specifics->set_use_custom_theme(use_custom_theme);
186   if (is_system_theme_distinct_from_default_theme) {
187     theme_specifics->set_use_system_theme_by_default(
188         use_system_theme_by_default);
189   } else {
190     DCHECK(!use_system_theme_by_default);
191   }
192   if (use_custom_theme) {
193     DCHECK(current_theme);
194     DCHECK(current_theme->is_theme());
195     theme_specifics->set_custom_theme_name(current_theme->name());
196     theme_specifics->set_custom_theme_id(current_theme->id());
197     theme_specifics->set_custom_theme_update_url(
198         current_theme->update_url().spec());
199   } else {
200     DCHECK(!current_theme);
201     theme_specifics->clear_custom_theme_name();
202     theme_specifics->clear_custom_theme_id();
203     theme_specifics->clear_custom_theme_update_url();
204   }
205 }
206 
SetCurrentThemeFromThemeSpecificsIfNecessary(const sync_pb::ThemeSpecifics & theme_specifics,Profile * profile)207 void SetCurrentThemeFromThemeSpecificsIfNecessary(
208     const sync_pb::ThemeSpecifics& theme_specifics, Profile* profile) {
209   DCHECK(profile);
210   sync_pb::ThemeSpecifics old_theme_specifics;
211   GetThemeSpecificsFromCurrentTheme(profile, &old_theme_specifics);
212   if (!AreThemeSpecificsEqual(old_theme_specifics, theme_specifics)) {
213     SetCurrentThemeFromThemeSpecifics(theme_specifics, profile);
214   }
215 }
216 
217 }  // namespace browser_sync
218