themes_helper.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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/test/integration/themes_helper.h"
6
7#include "base/callback.h"
8#include "base/logging.h"
9#include "base/strings/string_number_conversions.h"
10#include "base/strings/stringprintf.h"
11#include "chrome/browser/chrome_notification_types.h"
12#include "chrome/browser/sync/test/integration/status_change_checker.h"
13#include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
14#include "chrome/browser/sync/test/integration/sync_extension_helper.h"
15#include "chrome/browser/themes/theme_service.h"
16#include "chrome/browser/themes/theme_service_factory.h"
17#include "content/public/browser/notification_observer.h"
18#include "content/public/browser/notification_registrar.h"
19#include "content/public/browser/notification_source.h"
20#include "extensions/common/extension.h"
21#include "extensions/common/id_util.h"
22#include "extensions/common/manifest.h"
23
24using sync_datatype_helper::test;
25
26namespace {
27
28// Make a name to pass to an extension helper.
29std::string MakeName(int index) {
30  return "faketheme" + base::IntToString(index);
31}
32
33ThemeService* GetThemeService(Profile* profile) {
34  return ThemeServiceFactory::GetForProfile(profile);
35}
36
37}  // namespace
38
39namespace themes_helper {
40
41std::string GetCustomTheme(int index) {
42  return extensions::id_util::GenerateId(MakeName(index));
43}
44
45std::string GetThemeID(Profile* profile) {
46  return GetThemeService(profile)->GetThemeID();
47}
48
49bool UsingCustomTheme(Profile* profile) {
50  return GetThemeID(profile) != ThemeService::kDefaultThemeID;
51}
52
53bool UsingDefaultTheme(Profile* profile) {
54  return GetThemeService(profile)->UsingDefaultTheme();
55}
56
57bool UsingSystemTheme(Profile* profile) {
58  return GetThemeService(profile)->UsingSystemTheme();
59}
60
61bool ThemeIsPendingInstall(Profile* profile, const std::string& id) {
62  return SyncExtensionHelper::GetInstance()->
63      IsExtensionPendingInstallForSync(profile, id);
64}
65
66void UseCustomTheme(Profile* profile, int index) {
67  SyncExtensionHelper::GetInstance()->InstallExtension(
68      profile, MakeName(index), extensions::Manifest::TYPE_THEME);
69}
70
71void UseDefaultTheme(Profile* profile) {
72  GetThemeService(profile)->UseDefaultTheme();
73}
74
75void UseSystemTheme(Profile* profile) {
76  GetThemeService(profile)->UseSystemTheme();
77}
78
79namespace {
80
81// Helper to wait until the specified theme is pending for install on the
82// specified profile.
83//
84// The themes sync integration tests don't actually install any custom themes,
85// but they do occasionally check that the ThemeService attempts to install
86// synced themes.
87class ThemePendingInstallChecker : public StatusChangeChecker,
88                                   public content::NotificationObserver {
89 public:
90  ThemePendingInstallChecker(Profile* profile, const std::string& theme);
91  virtual ~ThemePendingInstallChecker();
92
93  // Implementation of StatusChangeChecker.
94  virtual std::string GetDebugMessage() const OVERRIDE;
95  virtual bool IsExitConditionSatisfied() OVERRIDE;
96
97  // Implementation of content::NotificationObserver.
98  virtual void Observe(int type,
99                       const content::NotificationSource& source,
100                       const content::NotificationDetails& details) OVERRIDE;
101
102  // Waits until the condition to be met or a timeout occurs.
103  void Wait();
104
105 private:
106  Profile* profile_;
107  const std::string& theme_;
108
109  content::NotificationRegistrar registrar_;
110};
111
112ThemePendingInstallChecker::ThemePendingInstallChecker(Profile* profile,
113                                                       const std::string& theme)
114    : profile_(profile), theme_(theme) {
115}
116
117ThemePendingInstallChecker::~ThemePendingInstallChecker() {
118}
119
120std::string ThemePendingInstallChecker::GetDebugMessage() const {
121  return base::StringPrintf("Waiting for pending theme to be '%s'",
122                            theme_.c_str());
123}
124
125bool ThemePendingInstallChecker::IsExitConditionSatisfied() {
126  return ThemeIsPendingInstall(profile_, theme_);
127}
128
129void ThemePendingInstallChecker::Observe(
130    int type,
131    const content::NotificationSource& source,
132    const content::NotificationDetails& details) {
133  DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UPDATING_STARTED, type);
134  CheckExitCondition();
135}
136
137void ThemePendingInstallChecker::Wait() {
138  // We'll check to see if the condition is met whenever the extension system
139  // tries to contact the web store.
140  registrar_.Add(this,
141                 chrome::NOTIFICATION_EXTENSION_UPDATING_STARTED,
142                 content::Source<Profile>(profile_));
143
144  if (IsExitConditionSatisfied()) {
145    return;
146  }
147
148  StartBlockingWait();
149}
150
151}  // namespace
152
153bool AwaitThemeIsPendingInstall(Profile* profile, const std::string& theme) {
154  ThemePendingInstallChecker checker(profile, theme);
155  checker.Wait();
156  return !checker.TimedOut();
157}
158
159namespace {
160
161// Helper to wait until a given condition is met, checking every time the
162// current theme changes.
163//
164// The |exit_condition_| closure may be invoked zero or more times.
165class ThemeConditionChecker : public StatusChangeChecker,
166                              public content::NotificationObserver {
167 public:
168  ThemeConditionChecker(Profile* profile,
169                        const std::string& debug_message_,
170                        base::Callback<bool(ThemeService*)> exit_condition);
171  virtual ~ThemeConditionChecker();
172
173  // Implementation of StatusChangeChecker.
174  virtual std::string GetDebugMessage() const OVERRIDE;
175  virtual bool IsExitConditionSatisfied() OVERRIDE;
176
177  // Implementation of content::NotificationObserver.
178  virtual void Observe(int type,
179                       const content::NotificationSource& source,
180                       const content::NotificationDetails& details) OVERRIDE;
181
182  // Waits until the condition to be met or a timeout occurs.
183  void Wait();
184
185 private:
186  Profile* profile_;
187  const std::string debug_message_;
188  base::Callback<bool(ThemeService*)> exit_condition_;
189
190  content::NotificationRegistrar registrar_;
191};
192
193ThemeConditionChecker::ThemeConditionChecker(
194    Profile* profile,
195    const std::string& debug_message,
196    base::Callback<bool(ThemeService*)> exit_condition)
197    : profile_(profile),
198      debug_message_(debug_message),
199      exit_condition_(exit_condition) {
200}
201
202ThemeConditionChecker::~ThemeConditionChecker() {
203}
204
205std::string ThemeConditionChecker::GetDebugMessage() const {
206  return debug_message_;
207}
208
209bool ThemeConditionChecker::IsExitConditionSatisfied() {
210  return exit_condition_.Run(GetThemeService(profile_));
211}
212
213void ThemeConditionChecker::Observe(
214    int type,
215    const content::NotificationSource& source,
216    const content::NotificationDetails& details) {
217  DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
218  CheckExitCondition();
219}
220
221void ThemeConditionChecker::Wait() {
222  registrar_.Add(this,
223                 chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
224                 content::Source<ThemeService>(GetThemeService(profile_)));
225
226  if (IsExitConditionSatisfied()) {
227    return;
228  }
229
230  StartBlockingWait();
231}
232
233// Helper function to let us bind this functionality into a base::Callback.
234bool UsingSystemThemeFunc(ThemeService* theme_service) {
235  return theme_service->UsingSystemTheme();
236}
237
238// Helper function to let us bind this functionality into a base::Callback.
239bool UsingDefaultThemeFunc(ThemeService* theme_service) {
240  return theme_service->UsingDefaultTheme();
241}
242
243}  // namespace
244
245bool AwaitUsingSystemTheme(Profile* profile) {
246  ThemeConditionChecker checker(
247      profile,
248      std::string("Waiting until profile is using system theme"),
249      base::Bind(&UsingSystemThemeFunc));
250  checker.Wait();
251  return !checker.TimedOut();
252}
253
254bool AwaitUsingDefaultTheme(Profile* profile) {
255  ThemeConditionChecker checker(
256      profile,
257      std::string("Waiting until profile is using default theme"),
258      base::Bind(&UsingDefaultThemeFunc));
259  checker.Wait();
260  return !checker.TimedOut();
261}
262
263}  // namespace themes_helper
264