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: 28 explicit Delegate(chromeos::LocaleChangeGuard* master) : master_(master) {} 29 void Close(bool by_user); 30 void Display() {} 31 void Error() {} 32 void Click() {} 33 std::string id() const; 34 35 private: 36 chromeos::LocaleChangeGuard* master_; 37 38 DISALLOW_COPY_AND_ASSIGN(Delegate); 39 }; 40 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 50 void LocaleChangeGuard::OnLogin() { 51 registrar_.Add(this, NotificationType::LOAD_COMPLETED_MAIN_FRAME, 52 NotificationService::AllSources()); 53 } 54 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 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 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 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 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 217 void LocaleChangeGuard::Delegate::Close(bool by_user) { 218 if (by_user) 219 master_->AcceptLocaleChange(); 220 } 221 222 std::string LocaleChangeGuard::Delegate::id() const { 223 // Arbitrary unique Id. 224 return "8c386938-1e3f-11e0-ac7b-18a90520e2e5"; 225 } 226 227 } // namespace chromeos 228