Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / locale_change_guard.cc
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 <algorithm>
8
9 #include "ash/shell.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"
31
32 using base::UserMetricsAction;
33 using content::WebContents;
34
35 namespace chromeos {
36
37 namespace {
38
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.
41 //
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"};
45
46 }  // anonymous namespace
47
48 LocaleChangeGuard::LocaleChangeGuard(Profile* profile)
49     : profile_(profile),
50       reverted_(false),
51       session_started_(false),
52       main_frame_loaded_(false) {
53   DCHECK(profile_);
54   registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
55                  content::NotificationService::AllSources());
56 }
57
58 LocaleChangeGuard::~LocaleChangeGuard() {}
59
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());
65 }
66
67 void LocaleChangeGuard::RevertLocaleChange() {
68   if (profile_ == NULL ||
69       from_locale_.empty() ||
70       to_locale_.empty()) {
71     NOTREACHED();
72     return;
73   }
74   if (reverted_)
75     return;
76   reverted_ = true;
77   content::RecordAction(UserMetricsAction("LanguageChange_Revert"));
78   profile_->ChangeAppLocale(
79       from_locale_, Profile::APP_LOCALE_CHANGED_VIA_REVERT);
80   chrome::AttemptUserExit();
81 }
82
83 void LocaleChangeGuard::RevertLocaleChangeCallback(
84     const base::ListValue* list) {
85   RevertLocaleChange();
86 }
87
88 void LocaleChangeGuard::Observe(int type,
89                                 const content::NotificationSource& source,
90                                 const content::NotificationDetails& details) {
91   if (profile_ == NULL) {
92     NOTREACHED();
93     return;
94   }
95   switch (type) {
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_)
101         Check();
102       break;
103     }
104     case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
105       if (profile_ ==
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_)
112           Check();
113       }
114       break;
115     }
116     case chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED: {
117       if (DeviceSettingsService::Get()->HasPrivateOwnerKey()) {
118         PrefService* local_state = g_browser_process->local_state();
119         if (local_state) {
120           PrefService* prefs = profile_->GetPrefs();
121           if (prefs == NULL) {
122             NOTREACHED();
123             return;
124           }
125           std::string owner_locale =
126               prefs->GetString(prefs::kApplicationLocale);
127           if (!owner_locale.empty())
128             local_state->SetString(prefs::kOwnerLocale, owner_locale);
129         }
130       }
131       break;
132     }
133     default: {
134       NOTREACHED();
135       break;
136     }
137   }
138 }
139
140 void LocaleChangeGuard::Check() {
141   std::string cur_locale = g_browser_process->GetApplicationLocale();
142   if (cur_locale.empty()) {
143     NOTREACHED();
144     return;
145   }
146
147   PrefService* prefs = profile_->GetPrefs();
148   if (prefs == NULL) {
149     NOTREACHED();
150     return;
151   }
152
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.
158     return;
159   }
160
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.
164
165   if (prefs->GetString(prefs::kApplicationLocaleAccepted) == to_locale)
166     return;  // Already accepted.
167
168   // Locale change detected.
169   if (!ShouldShowLocaleChangeNotification(from_locale, to_locale))
170     return;
171
172   // Showing notification.
173   if (from_locale_ != from_locale || to_locale_ != to_locale) {
174     // Falling back to showing message in current locale.
175     LOG(ERROR) <<
176         "Showing locale change notification in current (not previous) language";
177     PrepareChangingLocale(from_locale, to_locale);
178   }
179
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_);
184 #endif
185 }
186
187 void LocaleChangeGuard::AcceptLocaleChange() {
188   if (profile_ == NULL ||
189       from_locale_.empty() ||
190       to_locale_.empty()) {
191     NOTREACHED();
192     return;
193   }
194
195   // Check whether locale has been reverted or changed.
196   // If not: mark current locale as accepted.
197   if (reverted_)
198     return;
199   PrefService* prefs = profile_->GetPrefs();
200   if (prefs == NULL) {
201     NOTREACHED();
202     return;
203   }
204   if (prefs->GetString(prefs::kApplicationLocale) != to_locale_)
205     return;
206   content::RecordAction(UserMetricsAction("LanguageChange_Accept"));
207   prefs->SetString(prefs::kApplicationLocaleBackup, to_locale_);
208   prefs->SetString(prefs::kApplicationLocaleAccepted, to_locale_);
209 }
210
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;
218
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);
224
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);
231   }
232 }
233
234 // static
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);
240
241   if (from_locale == to_locale)
242     return false;
243
244   if (from_lang != to_lang)
245     return true;
246
247   const char* const* begin = kSkipShowNotificationLanguages;
248   const char* const* end = kSkipShowNotificationLanguages +
249                            arraysize(kSkipShowNotificationLanguages);
250
251   return std::find(begin, end, from_lang) == end;
252 }
253
254 // static
255 const char* const*
256 LocaleChangeGuard::GetSkipShowNotificationLanguagesForTesting() {
257   return kSkipShowNotificationLanguages;
258 }
259
260 // static
261 size_t LocaleChangeGuard::GetSkipShowNotificationLanguagesSizeForTesting() {
262   return arraysize(kSkipShowNotificationLanguages);
263 }
264
265 }  // namespace chromeos