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 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 46 LocaleChangeGuard::~LocaleChangeGuard() {} 47 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 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 71 void LocaleChangeGuard::RevertLocaleChangeCallback( 72 const base::ListValue* list) { 73 RevertLocaleChange(); 74 } 75 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 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 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 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