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.
5 #include "chrome/browser/chromeos/locale_change_guard.h"
10 #include "ash/system/tray/system_tray.h"
11 #include "ash/system/tray/system_tray_notifier.h"
12 #include "base/bind.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/app/chrome_command_ids.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/chromeos/settings/device_settings_service.h"
19 #include "chrome/browser/lifetime/application_lifetime.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_commands.h"
23 #include "chrome/browser/ui/host_desktop.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/grit/generated_resources.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_source.h"
28 #include "content/public/browser/user_metrics.h"
29 #include "content/public/browser/web_contents.h"
30 #include "ui/base/l10n/l10n_util.h"
32 using base::UserMetricsAction
;
33 using content::WebContents
;
39 // This is the list of languages that do not require user notification when
40 // locale is switched automatically between regions within the same language.
42 // New language in kAcceptLanguageList should be added either here or to
43 // to the exception list in unit test.
44 const char* const kSkipShowNotificationLanguages
[4] = {"en", "de", "fr", "it"};
46 } // anonymous namespace
48 LocaleChangeGuard::LocaleChangeGuard(Profile
* profile
)
51 session_started_(false),
52 main_frame_loaded_(false) {
54 registrar_
.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED
,
55 content::NotificationService::AllSources());
58 LocaleChangeGuard::~LocaleChangeGuard() {}
60 void LocaleChangeGuard::OnLogin() {
61 registrar_
.Add(this, chrome::NOTIFICATION_SESSION_STARTED
,
62 content::NotificationService::AllSources());
63 registrar_
.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
64 content::NotificationService::AllBrowserContextsAndSources());
67 void LocaleChangeGuard::RevertLocaleChange() {
68 if (profile_
== NULL
||
69 from_locale_
.empty() ||
77 content::RecordAction(UserMetricsAction("LanguageChange_Revert"));
78 profile_
->ChangeAppLocale(
79 from_locale_
, Profile::APP_LOCALE_CHANGED_VIA_REVERT
);
80 chrome::AttemptUserExit();
83 void LocaleChangeGuard::RevertLocaleChangeCallback(
84 const base::ListValue
* list
) {
88 void LocaleChangeGuard::Observe(int type
,
89 const content::NotificationSource
& source
,
90 const content::NotificationDetails
& details
) {
91 if (profile_
== NULL
) {
96 case chrome::NOTIFICATION_SESSION_STARTED
: {
97 session_started_
= true;
98 registrar_
.Remove(this, chrome::NOTIFICATION_SESSION_STARTED
,
99 content::NotificationService::AllSources());
100 if (main_frame_loaded_
)
104 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
: {
106 content::Source
<WebContents
>(source
)->GetBrowserContext()) {
107 main_frame_loaded_
= true;
108 // We need to perform locale change check only once, so unsubscribe.
109 registrar_
.Remove(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
110 content::NotificationService::AllSources());
111 if (session_started_
)
116 case chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED
: {
117 if (DeviceSettingsService::Get()->HasPrivateOwnerKey()) {
118 PrefService
* local_state
= g_browser_process
->local_state();
120 PrefService
* prefs
= profile_
->GetPrefs();
125 std::string owner_locale
=
126 prefs
->GetString(prefs::kApplicationLocale
);
127 if (!owner_locale
.empty())
128 local_state
->SetString(prefs::kOwnerLocale
, owner_locale
);
140 void LocaleChangeGuard::Check() {
141 std::string cur_locale
= g_browser_process
->GetApplicationLocale();
142 if (cur_locale
.empty()) {
147 PrefService
* prefs
= profile_
->GetPrefs();
153 std::string to_locale
= prefs
->GetString(prefs::kApplicationLocale
);
154 if (to_locale
!= cur_locale
) {
155 // This conditional branch can occur in cases like:
156 // (1) kApplicationLocale preference was modified by synchronization;
157 // (2) kApplicationLocale is managed by policy.
161 std::string from_locale
= prefs
->GetString(prefs::kApplicationLocaleBackup
);
162 if (from_locale
.empty() || from_locale
== to_locale
)
163 return; // No locale change was detected, just exit.
165 if (prefs
->GetString(prefs::kApplicationLocaleAccepted
) == to_locale
)
166 return; // Already accepted.
168 // Locale change detected.
169 if (!ShouldShowLocaleChangeNotification(from_locale
, to_locale
))
172 // Showing notification.
173 if (from_locale_
!= from_locale
|| to_locale_
!= to_locale
) {
174 // Falling back to showing message in current locale.
176 "Showing locale change notification in current (not previous) language";
177 PrepareChangingLocale(from_locale
, to_locale
);
180 #if !defined(USE_ATHENA)
181 // TODO(dpolukhin): Support locale change, crbug.com/411884.
182 ash::Shell::GetInstance()->system_tray_notifier()->NotifyLocaleChanged(
183 this, cur_locale
, from_locale_
, to_locale_
);
187 void LocaleChangeGuard::AcceptLocaleChange() {
188 if (profile_
== NULL
||
189 from_locale_
.empty() ||
190 to_locale_
.empty()) {
195 // Check whether locale has been reverted or changed.
196 // If not: mark current locale as accepted.
199 PrefService
* prefs
= profile_
->GetPrefs();
204 if (prefs
->GetString(prefs::kApplicationLocale
) != to_locale_
)
206 content::RecordAction(UserMetricsAction("LanguageChange_Accept"));
207 prefs
->SetString(prefs::kApplicationLocaleBackup
, to_locale_
);
208 prefs
->SetString(prefs::kApplicationLocaleAccepted
, to_locale_
);
211 void LocaleChangeGuard::PrepareChangingLocale(
212 const std::string
& from_locale
, const std::string
& to_locale
) {
213 std::string cur_locale
= g_browser_process
->GetApplicationLocale();
214 if (!from_locale
.empty())
215 from_locale_
= from_locale
;
216 if (!to_locale
.empty())
217 to_locale_
= to_locale
;
219 if (!from_locale_
.empty() && !to_locale_
.empty()) {
220 base::string16 from
= l10n_util::GetDisplayNameForLocale(
221 from_locale_
, cur_locale
, true);
222 base::string16 to
= l10n_util::GetDisplayNameForLocale(
223 to_locale_
, cur_locale
, true);
225 title_text_
= l10n_util::GetStringUTF16(
226 IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE
);
227 message_text_
= l10n_util::GetStringFUTF16(
228 IDS_LOCALE_CHANGE_MESSAGE
, from
, to
);
229 revert_link_text_
= l10n_util::GetStringFUTF16(
230 IDS_LOCALE_CHANGE_REVERT_MESSAGE
, from
);
235 bool LocaleChangeGuard::ShouldShowLocaleChangeNotification(
236 const std::string
& from_locale
,
237 const std::string
& to_locale
) {
238 const std::string from_lang
= l10n_util::GetLanguage(from_locale
);
239 const std::string to_lang
= l10n_util::GetLanguage(to_locale
);
241 if (from_locale
== to_locale
)
244 if (from_lang
!= to_lang
)
247 const char* const* begin
= kSkipShowNotificationLanguages
;
248 const char* const* end
= kSkipShowNotificationLanguages
+
249 arraysize(kSkipShowNotificationLanguages
);
251 return std::find(begin
, end
, from_lang
) == end
;
256 LocaleChangeGuard::GetSkipShowNotificationLanguagesForTesting() {
257 return kSkipShowNotificationLanguages
;
261 size_t LocaleChangeGuard::GetSkipShowNotificationLanguagesSizeForTesting() {
262 return arraysize(kSkipShowNotificationLanguages
);
265 } // namespace chromeos