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/chromeos/locale_change_guard.h"
6
7 #include "base/utf_string_conversions.h"
8 #include "chrome/app/chrome_command_ids.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/chromeos/login/user_manager.h"
11 #include "chrome/browser/metrics/user_metrics.h"
12 #include "chrome/browser/notifications/notification_delegate.h"
13 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/common/pref_names.h"
17 #include "content/browser/tab_contents/tab_contents.h"
18 #include "content/common/notification_service.h"
19 #include "content/common/notification_source.h"
20 #include "grit/generated_resources.h"
21 #include "grit/theme_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
23
24 namespace chromeos {
25
26 class LocaleChangeGuard::Delegate : public NotificationDelegate {
27 public:
Delegate(chromeos::LocaleChangeGuard * master)28 explicit Delegate(chromeos::LocaleChangeGuard* master) : master_(master) {}
29 void Close(bool by_user);
Display()30 void Display() {}
Error()31 void Error() {}
Click()32 void Click() {}
33 std::string id() const;
34
35 private:
36 chromeos::LocaleChangeGuard* master_;
37
38 DISALLOW_COPY_AND_ASSIGN(Delegate);
39 };
40
LocaleChangeGuard(Profile * profile)41 LocaleChangeGuard::LocaleChangeGuard(Profile* profile)
42 : profile_(profile),
43 note_(NULL),
44 reverted_(false) {
45 DCHECK(profile_);
46 registrar_.Add(this, NotificationType::OWNERSHIP_CHECKED,
47 NotificationService::AllSources());
48 }
49
OnLogin()50 void LocaleChangeGuard::OnLogin() {
51 registrar_.Add(this, NotificationType::LOAD_COMPLETED_MAIN_FRAME,
52 NotificationService::AllSources());
53 }
54
RevertLocaleChange(const ListValue * list)55 void LocaleChangeGuard::RevertLocaleChange(const ListValue* list) {
56 if (note_ == NULL ||
57 profile_ == NULL ||
58 from_locale_.empty() ||
59 to_locale_.empty()) {
60 NOTREACHED();
61 return;
62 }
63 if (reverted_)
64 return;
65 reverted_ = true;
66 UserMetrics::RecordAction(UserMetricsAction("LanguageChange_Revert"));
67 profile_->ChangeAppLocale(
68 from_locale_, Profile::APP_LOCALE_CHANGED_VIA_REVERT);
69
70 Browser* browser = Browser::GetTabbedBrowser(profile_, false);
71 if (browser)
72 browser->ExecuteCommand(IDC_EXIT);
73 }
74
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)75 void LocaleChangeGuard::Observe(NotificationType type,
76 const NotificationSource& source,
77 const NotificationDetails& details) {
78 if (profile_ == NULL) {
79 NOTREACHED();
80 return;
81 }
82 switch (type.value) {
83 case NotificationType::LOAD_COMPLETED_MAIN_FRAME: {
84 // We need to perform locale change check only once, so unsubscribe.
85 registrar_.Remove(this, NotificationType::LOAD_COMPLETED_MAIN_FRAME,
86 NotificationService::AllSources());
87 Check();
88 break;
89 }
90 case NotificationType::OWNERSHIP_CHECKED: {
91 if (UserManager::Get()->current_user_is_owner()) {
92 PrefService* local_state = g_browser_process->local_state();
93 if (local_state) {
94 PrefService* prefs = profile_->GetPrefs();
95 if (prefs == NULL) {
96 NOTREACHED();
97 return;
98 }
99 std::string owner_locale =
100 prefs->GetString(prefs::kApplicationLocale);
101 if (!owner_locale.empty()) {
102 local_state->SetString(prefs::kOwnerLocale, owner_locale);
103 local_state->ScheduleSavePersistentPrefs();
104 }
105 }
106 }
107 break;
108 }
109 default: {
110 NOTREACHED();
111 break;
112 }
113 }
114 }
115
Check()116 void LocaleChangeGuard::Check() {
117 if (note_ != NULL) {
118 // Somehow we are invoked more than once. Once is enough.
119 return;
120 }
121
122 std::string cur_locale = g_browser_process->GetApplicationLocale();
123 if (cur_locale.empty()) {
124 NOTREACHED();
125 return;
126 }
127
128 PrefService* prefs = profile_->GetPrefs();
129 if (prefs == NULL) {
130 NOTREACHED();
131 return;
132 }
133
134 std::string to_locale = prefs->GetString(prefs::kApplicationLocale);
135 if (to_locale != cur_locale) {
136 // This conditional branch can occur in cases like:
137 // (1) kApplicationLocale preference was modified by synchronization;
138 // (2) kApplicationLocale is managed by policy.
139 return;
140 }
141
142 std::string from_locale = prefs->GetString(prefs::kApplicationLocaleBackup);
143 if (from_locale.empty() || from_locale == to_locale)
144 return; // No locale change was detected, just exit.
145
146 if (prefs->GetString(prefs::kApplicationLocaleAccepted) == to_locale)
147 return; // Already accepted.
148
149 // Locale change detected, showing notification.
150 if (from_locale_ != from_locale || to_locale_ != to_locale) {
151 // Falling back to showing message in current locale.
152 LOG(ERROR) <<
153 "Showing locale change notification in current (not previous) language";
154 PrepareChangingLocale(from_locale, to_locale);
155 }
156 note_.reset(new chromeos::SystemNotification(
157 profile_,
158 new Delegate(this),
159 IDR_NOTIFICATION_LOCALE_CHANGE,
160 title_text_));
161 note_->Show(
162 message_text_, revert_link_text_,
163 NewCallback(this, &LocaleChangeGuard::RevertLocaleChange),
164 true, // urgent
165 false); // non-sticky
166 }
167
AcceptLocaleChange()168 void LocaleChangeGuard::AcceptLocaleChange() {
169 if (note_ == NULL ||
170 profile_ == NULL ||
171 from_locale_.empty() ||
172 to_locale_.empty()) {
173 NOTREACHED();
174 return;
175 }
176
177 // Check whether locale has been reverted or changed.
178 // If not: mark current locale as accepted.
179 if (reverted_)
180 return;
181 PrefService* prefs = profile_->GetPrefs();
182 if (prefs == NULL) {
183 NOTREACHED();
184 return;
185 }
186 if (prefs->GetString(prefs::kApplicationLocale) != to_locale_)
187 return;
188 UserMetrics::RecordAction(UserMetricsAction("LanguageChange_Accept"));
189 prefs->SetString(prefs::kApplicationLocaleBackup, to_locale_);
190 prefs->SetString(prefs::kApplicationLocaleAccepted, to_locale_);
191 prefs->ScheduleSavePersistentPrefs();
192 }
193
PrepareChangingLocale(const std::string & from_locale,const std::string & to_locale)194 void LocaleChangeGuard::PrepareChangingLocale(
195 const std::string& from_locale, const std::string& to_locale) {
196 std::string cur_locale = g_browser_process->GetApplicationLocale();
197 if (!from_locale.empty())
198 from_locale_ = from_locale;
199 if (!to_locale.empty())
200 to_locale_ = to_locale;
201
202 if (!from_locale_.empty() && !to_locale_.empty()) {
203 string16 from = l10n_util::GetDisplayNameForLocale(
204 from_locale_, cur_locale, true);
205 string16 to = l10n_util::GetDisplayNameForLocale(
206 to_locale_, cur_locale, true);
207
208 title_text_ = l10n_util::GetStringUTF16(
209 IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE);
210 message_text_ = l10n_util::GetStringFUTF16(
211 IDS_LOCALE_CHANGE_MESSAGE, from, to);
212 revert_link_text_ = l10n_util::GetStringFUTF16(
213 IDS_LOCALE_CHANGE_REVERT_MESSAGE, from);
214 }
215 }
216
Close(bool by_user)217 void LocaleChangeGuard::Delegate::Close(bool by_user) {
218 if (by_user)
219 master_->AcceptLocaleChange();
220 }
221
id() const222 std::string LocaleChangeGuard::Delegate::id() const {
223 // Arbitrary unique Id.
224 return "8c386938-1e3f-11e0-ac7b-18a90520e2e5";
225 }
226
227 } // namespace chromeos
228