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/profiles/profile.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_commands.h"
21 #include "chrome/browser/ui/host_desktop.h"
22 #include "chrome/common/pref_names.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/user_metrics.h"
26 #include "content/public/browser/web_contents.h"
27 #include "grit/generated_resources.h"
28 #include "grit/theme_resources.h"
29 #include "ui/base/l10n/l10n_util.h"
30
31 using base::UserMetricsAction;
32 using content::WebContents;
33
34 namespace chromeos {
35
LocaleChangeGuard(Profile * profile)36 LocaleChangeGuard::LocaleChangeGuard(Profile* profile)
37 : profile_(profile),
38 reverted_(false),
39 session_started_(false),
40 main_frame_loaded_(false) {
41 DCHECK(profile_);
42 registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
43 content::NotificationService::AllSources());
44 }
45
~LocaleChangeGuard()46 LocaleChangeGuard::~LocaleChangeGuard() {}
47
OnLogin()48 void LocaleChangeGuard::OnLogin() {
49 registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED,
50 content::NotificationService::AllSources());
51 registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
52 content::NotificationService::AllBrowserContextsAndSources());
53 }
54
RevertLocaleChange()55 void LocaleChangeGuard::RevertLocaleChange() {
56 if (profile_ == NULL ||
57 from_locale_.empty() ||
58 to_locale_.empty()) {
59 NOTREACHED();
60 return;
61 }
62 if (reverted_)
63 return;
64 reverted_ = true;
65 content::RecordAction(UserMetricsAction("LanguageChange_Revert"));
66 profile_->ChangeAppLocale(
67 from_locale_, Profile::APP_LOCALE_CHANGED_VIA_REVERT);
68 chrome::AttemptUserExit();
69 }
70
RevertLocaleChangeCallback(const base::ListValue * list)71 void LocaleChangeGuard::RevertLocaleChangeCallback(
72 const base::ListValue* list) {
73 RevertLocaleChange();
74 }
75
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)76 void LocaleChangeGuard::Observe(int type,
77 const content::NotificationSource& source,
78 const content::NotificationDetails& details) {
79 if (profile_ == NULL) {
80 NOTREACHED();
81 return;
82 }
83 switch (type) {
84 case chrome::NOTIFICATION_SESSION_STARTED: {
85 session_started_ = true;
86 registrar_.Remove(this, chrome::NOTIFICATION_SESSION_STARTED,
87 content::NotificationService::AllSources());
88 if (main_frame_loaded_)
89 Check();
90 break;
91 }
92 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
93 if (profile_ ==
94 content::Source<WebContents>(source)->GetBrowserContext()) {
95 main_frame_loaded_ = true;
96 // We need to perform locale change check only once, so unsubscribe.
97 registrar_.Remove(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
98 content::NotificationService::AllSources());
99 if (session_started_)
100 Check();
101 }
102 break;
103 }
104 case chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED: {
105 if (DeviceSettingsService::Get()->HasPrivateOwnerKey()) {
106 PrefService* local_state = g_browser_process->local_state();
107 if (local_state) {
108 PrefService* prefs = profile_->GetPrefs();
109 if (prefs == NULL) {
110 NOTREACHED();
111 return;
112 }
113 std::string owner_locale =
114 prefs->GetString(prefs::kApplicationLocale);
115 if (!owner_locale.empty())
116 local_state->SetString(prefs::kOwnerLocale, owner_locale);
117 }
118 }
119 break;
120 }
121 default: {
122 NOTREACHED();
123 break;
124 }
125 }
126 }
127
Check()128 void LocaleChangeGuard::Check() {
129 std::string cur_locale = g_browser_process->GetApplicationLocale();
130 if (cur_locale.empty()) {
131 NOTREACHED();
132 return;
133 }
134
135 PrefService* prefs = profile_->GetPrefs();
136 if (prefs == NULL) {
137 NOTREACHED();
138 return;
139 }
140
141 std::string to_locale = prefs->GetString(prefs::kApplicationLocale);
142 if (to_locale != cur_locale) {
143 // This conditional branch can occur in cases like:
144 // (1) kApplicationLocale preference was modified by synchronization;
145 // (2) kApplicationLocale is managed by policy.
146 return;
147 }
148
149 std::string from_locale = prefs->GetString(prefs::kApplicationLocaleBackup);
150 if (from_locale.empty() || from_locale == to_locale)
151 return; // No locale change was detected, just exit.
152
153 if (prefs->GetString(prefs::kApplicationLocaleAccepted) == to_locale)
154 return; // Already accepted.
155
156 // Locale change detected, showing notification.
157 if (from_locale_ != from_locale || to_locale_ != to_locale) {
158 // Falling back to showing message in current locale.
159 LOG(ERROR) <<
160 "Showing locale change notification in current (not previous) language";
161 PrepareChangingLocale(from_locale, to_locale);
162 }
163
164 ash::Shell::GetInstance()->system_tray_notifier()->NotifyLocaleChanged(
165 this, cur_locale, from_locale_, to_locale_);
166 }
167
AcceptLocaleChange()168 void LocaleChangeGuard::AcceptLocaleChange() {
169 if (profile_ == NULL ||
170 from_locale_.empty() ||
171 to_locale_.empty()) {
172 NOTREACHED();
173 return;
174 }
175
176 // Check whether locale has been reverted or changed.
177 // If not: mark current locale as accepted.
178 if (reverted_)
179 return;
180 PrefService* prefs = profile_->GetPrefs();
181 if (prefs == NULL) {
182 NOTREACHED();
183 return;
184 }
185 if (prefs->GetString(prefs::kApplicationLocale) != to_locale_)
186 return;
187 content::RecordAction(UserMetricsAction("LanguageChange_Accept"));
188 prefs->SetString(prefs::kApplicationLocaleBackup, to_locale_);
189 prefs->SetString(prefs::kApplicationLocaleAccepted, to_locale_);
190 }
191
PrepareChangingLocale(const std::string & from_locale,const std::string & to_locale)192 void LocaleChangeGuard::PrepareChangingLocale(
193 const std::string& from_locale, const std::string& to_locale) {
194 std::string cur_locale = g_browser_process->GetApplicationLocale();
195 if (!from_locale.empty())
196 from_locale_ = from_locale;
197 if (!to_locale.empty())
198 to_locale_ = to_locale;
199
200 if (!from_locale_.empty() && !to_locale_.empty()) {
201 base::string16 from = l10n_util::GetDisplayNameForLocale(
202 from_locale_, cur_locale, true);
203 base::string16 to = l10n_util::GetDisplayNameForLocale(
204 to_locale_, cur_locale, true);
205
206 title_text_ = l10n_util::GetStringUTF16(
207 IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE);
208 message_text_ = l10n_util::GetStringFUTF16(
209 IDS_LOCALE_CHANGE_MESSAGE, from, to);
210 revert_link_text_ = l10n_util::GetStringFUTF16(
211 IDS_LOCALE_CHANGE_REVERT_MESSAGE, from);
212 }
213 }
214
215 } // namespace chromeos
216