• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/locale_change_guard.h"
6 
7 #include "ash/shell.h"
8 #include "ash/system/tray/system_tray.h"
9 #include "ash/system/tray/system_tray_notifier.h"
10 #include "base/bind.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/app/chrome_command_ids.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/chromeos/settings/device_settings_service.h"
17 #include "chrome/browser/lifetime/application_lifetime.h"
18 #include "chrome/browser/notifications/notification_delegate.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_commands.h"
22 #include "chrome/browser/ui/host_desktop.h"
23 #include "chrome/common/pref_names.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/user_metrics.h"
27 #include "content/public/browser/web_contents.h"
28 #include "grit/generated_resources.h"
29 #include "grit/theme_resources.h"
30 #include "ui/base/l10n/l10n_util.h"
31 
32 using content::UserMetricsAction;
33 using content::WebContents;
34 
35 namespace chromeos {
36 
37 class LocaleChangeGuard::Delegate : public NotificationDelegate {
38  public:
Delegate(chromeos::LocaleChangeGuard * master)39   explicit Delegate(chromeos::LocaleChangeGuard* master) : master_(master) {}
40   virtual void Close(bool by_user) OVERRIDE;
Display()41   virtual void Display() OVERRIDE {}
Error()42   virtual void Error() OVERRIDE {}
Click()43   virtual void Click() OVERRIDE {}
44   virtual std::string id() const OVERRIDE;
GetRenderViewHost() const45   virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
46     return NULL;
47   }
48 
49  protected:
~Delegate()50   virtual ~Delegate() {}
51 
52  private:
53   chromeos::LocaleChangeGuard* master_;
54 
55   DISALLOW_COPY_AND_ASSIGN(Delegate);
56 };
57 
LocaleChangeGuard(Profile * profile)58 LocaleChangeGuard::LocaleChangeGuard(Profile* profile)
59     : profile_(profile),
60       reverted_(false),
61       session_started_(false),
62       main_frame_loaded_(false) {
63   DCHECK(profile_);
64   registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
65                  content::NotificationService::AllSources());
66 }
67 
~LocaleChangeGuard()68 LocaleChangeGuard::~LocaleChangeGuard() {}
69 
OnLogin()70 void LocaleChangeGuard::OnLogin() {
71   registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED,
72                  content::NotificationService::AllSources());
73   registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
74                  content::NotificationService::AllBrowserContextsAndSources());
75 }
76 
RevertLocaleChange()77 void LocaleChangeGuard::RevertLocaleChange() {
78   if (profile_ == NULL ||
79       from_locale_.empty() ||
80       to_locale_.empty()) {
81     NOTREACHED();
82     return;
83   }
84   if (reverted_)
85     return;
86   reverted_ = true;
87   content::RecordAction(UserMetricsAction("LanguageChange_Revert"));
88   profile_->ChangeAppLocale(
89       from_locale_, Profile::APP_LOCALE_CHANGED_VIA_REVERT);
90   chrome::AttemptUserExit();
91 }
92 
RevertLocaleChangeCallback(const ListValue * list)93 void LocaleChangeGuard::RevertLocaleChangeCallback(const ListValue* list) {
94   RevertLocaleChange();
95 }
96 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)97 void LocaleChangeGuard::Observe(int type,
98                                 const content::NotificationSource& source,
99                                 const content::NotificationDetails& details) {
100   if (profile_ == NULL) {
101     NOTREACHED();
102     return;
103   }
104   switch (type) {
105     case chrome::NOTIFICATION_SESSION_STARTED: {
106       session_started_ = true;
107       registrar_.Remove(this, chrome::NOTIFICATION_SESSION_STARTED,
108                         content::NotificationService::AllSources());
109       if (main_frame_loaded_)
110         Check();
111       break;
112     }
113     case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
114       if (profile_ ==
115           content::Source<WebContents>(source)->GetBrowserContext()) {
116         main_frame_loaded_ = true;
117         // We need to perform locale change check only once, so unsubscribe.
118         registrar_.Remove(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
119                           content::NotificationService::AllSources());
120         if (session_started_)
121           Check();
122       }
123       break;
124     }
125     case chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED: {
126       if (DeviceSettingsService::Get()->HasPrivateOwnerKey()) {
127         PrefService* local_state = g_browser_process->local_state();
128         if (local_state) {
129           PrefService* prefs = profile_->GetPrefs();
130           if (prefs == NULL) {
131             NOTREACHED();
132             return;
133           }
134           std::string owner_locale =
135               prefs->GetString(prefs::kApplicationLocale);
136           if (!owner_locale.empty())
137             local_state->SetString(prefs::kOwnerLocale, owner_locale);
138         }
139       }
140       break;
141     }
142     default: {
143       NOTREACHED();
144       break;
145     }
146   }
147 }
148 
Check()149 void LocaleChangeGuard::Check() {
150   std::string cur_locale = g_browser_process->GetApplicationLocale();
151   if (cur_locale.empty()) {
152     NOTREACHED();
153     return;
154   }
155 
156   PrefService* prefs = profile_->GetPrefs();
157   if (prefs == NULL) {
158     NOTREACHED();
159     return;
160   }
161 
162   std::string to_locale = prefs->GetString(prefs::kApplicationLocale);
163   if (to_locale != cur_locale) {
164     // This conditional branch can occur in cases like:
165     // (1) kApplicationLocale preference was modified by synchronization;
166     // (2) kApplicationLocale is managed by policy.
167     return;
168   }
169 
170   std::string from_locale = prefs->GetString(prefs::kApplicationLocaleBackup);
171   if (from_locale.empty() || from_locale == to_locale)
172     return;  // No locale change was detected, just exit.
173 
174   if (prefs->GetString(prefs::kApplicationLocaleAccepted) == to_locale)
175     return;  // Already accepted.
176 
177   // Locale change detected, showing notification.
178   if (from_locale_ != from_locale || to_locale_ != to_locale) {
179     // Falling back to showing message in current locale.
180     LOG(ERROR) <<
181         "Showing locale change notification in current (not previous) language";
182     PrepareChangingLocale(from_locale, to_locale);
183   }
184 
185   ash::Shell::GetInstance()->system_tray_notifier()->NotifyLocaleChanged(
186       this, cur_locale, from_locale_, to_locale_);
187 }
188 
AcceptLocaleChange()189 void LocaleChangeGuard::AcceptLocaleChange() {
190   if (profile_ == NULL ||
191       from_locale_.empty() ||
192       to_locale_.empty()) {
193     NOTREACHED();
194     return;
195   }
196 
197   // Check whether locale has been reverted or changed.
198   // If not: mark current locale as accepted.
199   if (reverted_)
200     return;
201   PrefService* prefs = profile_->GetPrefs();
202   if (prefs == NULL) {
203     NOTREACHED();
204     return;
205   }
206   if (prefs->GetString(prefs::kApplicationLocale) != to_locale_)
207     return;
208   content::RecordAction(UserMetricsAction("LanguageChange_Accept"));
209   prefs->SetString(prefs::kApplicationLocaleBackup, to_locale_);
210   prefs->SetString(prefs::kApplicationLocaleAccepted, to_locale_);
211 }
212 
PrepareChangingLocale(const std::string & from_locale,const std::string & to_locale)213 void LocaleChangeGuard::PrepareChangingLocale(
214     const std::string& from_locale, const std::string& to_locale) {
215   std::string cur_locale = g_browser_process->GetApplicationLocale();
216   if (!from_locale.empty())
217     from_locale_ = from_locale;
218   if (!to_locale.empty())
219     to_locale_ = to_locale;
220 
221   if (!from_locale_.empty() && !to_locale_.empty()) {
222     base::string16 from = l10n_util::GetDisplayNameForLocale(
223         from_locale_, cur_locale, true);
224     base::string16 to = l10n_util::GetDisplayNameForLocale(
225         to_locale_, cur_locale, true);
226 
227     title_text_ = l10n_util::GetStringUTF16(
228         IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE);
229     message_text_ = l10n_util::GetStringFUTF16(
230         IDS_LOCALE_CHANGE_MESSAGE, from, to);
231     revert_link_text_ = l10n_util::GetStringFUTF16(
232         IDS_LOCALE_CHANGE_REVERT_MESSAGE, from);
233   }
234 }
235 
Close(bool by_user)236 void LocaleChangeGuard::Delegate::Close(bool by_user) {
237   if (by_user)
238     master_->AcceptLocaleChange();
239 }
240 
id() const241 std::string LocaleChangeGuard::Delegate::id() const {
242   // Arbitrary unique Id.
243   return "8c386938-1e3f-11e0-ac7b-18a90520e2e5";
244 }
245 
246 }  // namespace chromeos
247