Home | History | Annotate | Download | only in chromeos
      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