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