Home | History | Annotate | Download | only in chromeos
      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/notifications/notification_delegate.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/browser.h"
     21 #include "chrome/browser/ui/browser_commands.h"
     22 #include "chrome/browser/ui/host_desktop.h"
     23 #include "chrome/common/pref_names.h"
     24 #include "content/public/browser/notification_service.h"
     25 #include "content/public/browser/notification_source.h"
     26 #include "content/public/browser/user_metrics.h"
     27 #include "content/public/browser/web_contents.h"
     28 #include "grit/generated_resources.h"
     29 #include "grit/theme_resources.h"
     30 #include "ui/base/l10n/l10n_util.h"
     31 
     32 using content::UserMetricsAction;
     33 using content::WebContents;
     34 
     35 namespace chromeos {
     36 
     37 class LocaleChangeGuard::Delegate : public NotificationDelegate {
     38  public:
     39   explicit Delegate(chromeos::LocaleChangeGuard* master) : master_(master) {}
     40   virtual void Close(bool by_user) OVERRIDE;
     41   virtual void Display() OVERRIDE {}
     42   virtual void Error() OVERRIDE {}
     43   virtual void Click() OVERRIDE {}
     44   virtual std::string id() const OVERRIDE;
     45   virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
     46     return NULL;
     47   }
     48 
     49  protected:
     50   virtual ~Delegate() {}
     51 
     52  private:
     53   chromeos::LocaleChangeGuard* master_;
     54 
     55   DISALLOW_COPY_AND_ASSIGN(Delegate);
     56 };
     57 
     58 LocaleChangeGuard::LocaleChangeGuard(Profile* profile)
     59     : profile_(profile),
     60       reverted_(false),
     61       session_started_(false),
     62       main_frame_loaded_(false) {
     63   DCHECK(profile_);
     64   registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
     65                  content::NotificationService::AllSources());
     66 }
     67 
     68 LocaleChangeGuard::~LocaleChangeGuard() {}
     69 
     70 void LocaleChangeGuard::OnLogin() {
     71   registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED,
     72                  content::NotificationService::AllSources());
     73   registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
     74                  content::NotificationService::AllBrowserContextsAndSources());
     75 }
     76 
     77 void LocaleChangeGuard::RevertLocaleChange() {
     78   if (profile_ == NULL ||
     79       from_locale_.empty() ||
     80       to_locale_.empty()) {
     81     NOTREACHED();
     82     return;
     83   }
     84   if (reverted_)
     85     return;
     86   reverted_ = true;
     87   content::RecordAction(UserMetricsAction("LanguageChange_Revert"));
     88   profile_->ChangeAppLocale(
     89       from_locale_, Profile::APP_LOCALE_CHANGED_VIA_REVERT);
     90   chrome::AttemptUserExit();
     91 }
     92 
     93 void LocaleChangeGuard::RevertLocaleChangeCallback(const ListValue* list) {
     94   RevertLocaleChange();
     95 }
     96 
     97 void LocaleChangeGuard::Observe(int type,
     98                                 const content::NotificationSource& source,
     99                                 const content::NotificationDetails& details) {
    100   if (profile_ == NULL) {
    101     NOTREACHED();
    102     return;
    103   }
    104   switch (type) {
    105     case chrome::NOTIFICATION_SESSION_STARTED: {
    106       session_started_ = true;
    107       registrar_.Remove(this, chrome::NOTIFICATION_SESSION_STARTED,
    108                         content::NotificationService::AllSources());
    109       if (main_frame_loaded_)
    110         Check();
    111       break;
    112     }
    113     case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
    114       if (profile_ ==
    115           content::Source<WebContents>(source)->GetBrowserContext()) {
    116         main_frame_loaded_ = true;
    117         // We need to perform locale change check only once, so unsubscribe.
    118         registrar_.Remove(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
    119                           content::NotificationService::AllSources());
    120         if (session_started_)
    121           Check();
    122       }
    123       break;
    124     }
    125     case chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED: {
    126       if (DeviceSettingsService::Get()->HasPrivateOwnerKey()) {
    127         PrefService* local_state = g_browser_process->local_state();
    128         if (local_state) {
    129           PrefService* prefs = profile_->GetPrefs();
    130           if (prefs == NULL) {
    131             NOTREACHED();
    132             return;
    133           }
    134           std::string owner_locale =
    135               prefs->GetString(prefs::kApplicationLocale);
    136           if (!owner_locale.empty())
    137             local_state->SetString(prefs::kOwnerLocale, owner_locale);
    138         }
    139       }
    140       break;
    141     }
    142     default: {
    143       NOTREACHED();
    144       break;
    145     }
    146   }
    147 }
    148 
    149 void LocaleChangeGuard::Check() {
    150   std::string cur_locale = g_browser_process->GetApplicationLocale();
    151   if (cur_locale.empty()) {
    152     NOTREACHED();
    153     return;
    154   }
    155 
    156   PrefService* prefs = profile_->GetPrefs();
    157   if (prefs == NULL) {
    158     NOTREACHED();
    159     return;
    160   }
    161 
    162   std::string to_locale = prefs->GetString(prefs::kApplicationLocale);
    163   if (to_locale != cur_locale) {
    164     // This conditional branch can occur in cases like:
    165     // (1) kApplicationLocale preference was modified by synchronization;
    166     // (2) kApplicationLocale is managed by policy.
    167     return;
    168   }
    169 
    170   std::string from_locale = prefs->GetString(prefs::kApplicationLocaleBackup);
    171   if (from_locale.empty() || from_locale == to_locale)
    172     return;  // No locale change was detected, just exit.
    173 
    174   if (prefs->GetString(prefs::kApplicationLocaleAccepted) == to_locale)
    175     return;  // Already accepted.
    176 
    177   // Locale change detected, showing notification.
    178   if (from_locale_ != from_locale || to_locale_ != to_locale) {
    179     // Falling back to showing message in current locale.
    180     LOG(ERROR) <<
    181         "Showing locale change notification in current (not previous) language";
    182     PrepareChangingLocale(from_locale, to_locale);
    183   }
    184 
    185   ash::Shell::GetInstance()->system_tray_notifier()->NotifyLocaleChanged(
    186       this, cur_locale, from_locale_, to_locale_);
    187 }
    188 
    189 void LocaleChangeGuard::AcceptLocaleChange() {
    190   if (profile_ == NULL ||
    191       from_locale_.empty() ||
    192       to_locale_.empty()) {
    193     NOTREACHED();
    194     return;
    195   }
    196 
    197   // Check whether locale has been reverted or changed.
    198   // If not: mark current locale as accepted.
    199   if (reverted_)
    200     return;
    201   PrefService* prefs = profile_->GetPrefs();
    202   if (prefs == NULL) {
    203     NOTREACHED();
    204     return;
    205   }
    206   if (prefs->GetString(prefs::kApplicationLocale) != to_locale_)
    207     return;
    208   content::RecordAction(UserMetricsAction("LanguageChange_Accept"));
    209   prefs->SetString(prefs::kApplicationLocaleBackup, to_locale_);
    210   prefs->SetString(prefs::kApplicationLocaleAccepted, to_locale_);
    211 }
    212 
    213 void LocaleChangeGuard::PrepareChangingLocale(
    214     const std::string& from_locale, const std::string& to_locale) {
    215   std::string cur_locale = g_browser_process->GetApplicationLocale();
    216   if (!from_locale.empty())
    217     from_locale_ = from_locale;
    218   if (!to_locale.empty())
    219     to_locale_ = to_locale;
    220 
    221   if (!from_locale_.empty() && !to_locale_.empty()) {
    222     base::string16 from = l10n_util::GetDisplayNameForLocale(
    223         from_locale_, cur_locale, true);
    224     base::string16 to = l10n_util::GetDisplayNameForLocale(
    225         to_locale_, cur_locale, true);
    226 
    227     title_text_ = l10n_util::GetStringUTF16(
    228         IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE);
    229     message_text_ = l10n_util::GetStringFUTF16(
    230         IDS_LOCALE_CHANGE_MESSAGE, from, to);
    231     revert_link_text_ = l10n_util::GetStringFUTF16(
    232         IDS_LOCALE_CHANGE_REVERT_MESSAGE, from);
    233   }
    234 }
    235 
    236 void LocaleChangeGuard::Delegate::Close(bool by_user) {
    237   if (by_user)
    238     master_->AcceptLocaleChange();
    239 }
    240 
    241 std::string LocaleChangeGuard::Delegate::id() const {
    242   // Arbitrary unique Id.
    243   return "8c386938-1e3f-11e0-ac7b-18a90520e2e5";
    244 }
    245 
    246 }  // namespace chromeos
    247