For ChromeOS: when starting session:
if locale was changed (as a result of sync or because user preference differs from login locale): show notification.

BUG=chromium-os:9164
TEST=Manual

Review URL: http://codereview.chromium.org/5976005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71320 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 5f4cdd76..a6dc68a 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4338,6 +4338,16 @@
         You are using an unsupported command-line flag: <ph name="BAD_FLAG">$1<ex>--no-sandbox</ex></ph>. Stability and security will suffer.
       </message>
 
+      <!-- Locale Change Notification-->
+      <if expr="pp_ifdef('chromeos')">
+        <message name="IDS_LOCALE_CHANGE_MESSAGE" desc="Message shown when locale was changed based on profile content.">
+          Interface language was changed: "<ph name="FROM_LOCALE">$1</ph>" => "<ph name="TO_LOCALE">$2</ph>" based on your preference.
+        </message>
+        <message name="IDS_LOCALE_CHANGE_REVERT_MESSAGE" desc="Link to revert a change.">
+          If you are unhappy about it: click here to close browser, sign out and revert.
+        </message>
+      </if>
+ 
       <if expr="pp_ifdef('chromeos')">
         <!-- about:system strings -->
         <message name="IDS_ABOUT_SYS_TITLE" desc="about:system page title">
diff --git a/chrome/browser/chromeos/dom_ui/language_options_handler.cc b/chrome/browser/chromeos/dom_ui/language_options_handler.cc
index b4c1b19..da2e692 100644
--- a/chrome/browser/chromeos/dom_ui/language_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/language_options_handler.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -289,18 +289,7 @@
   const std::string action = StringPrintf(
       "LanguageOptions_UiLanguageChange_%s", language_code.c_str());
   UserMetrics::RecordComputedAction(action);
-
-  // We maintain kApplicationLocale property in both a global storage
-  // and user's profile.  Global property determines locale of login screen,
-  // while user's profile determines his personal locale preference.
-  PrefService* prefs[] = {
-      g_browser_process->local_state(),
-      dom_ui_->GetProfile()->GetPrefs()
-  };
-  for (size_t i = 0; i < arraysize(prefs); ++i) {
-    prefs[i]->SetString(prefs::kApplicationLocale, language_code);
-    prefs[i]->SavePersistentPrefs();
-  }
+  dom_ui_->GetProfile()->ChangeApplicationLocale(language_code, false);
   dom_ui_->CallJavascriptFunction(
       L"options.LanguageOptions.uiLanguageSaved");
 }
diff --git a/chrome/browser/chromeos/locale_change_guard.cc b/chrome/browser/chromeos/locale_change_guard.cc
new file mode 100644
index 0000000..f875cdf5
--- /dev/null
+++ b/chrome/browser/chromeos/locale_change_guard.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/locale_change_guard.h"
+
+#include "app/l10n_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/pref_names.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+base::LazyInstance<chromeos::LocaleChangeGuard> g_locale_change_guard(
+    base::LINKER_INITIALIZED);
+
+}  // namespace
+
+namespace chromeos {
+
+LocaleChangeGuard::LocaleChangeGuard()
+    : profile_id_(Profile::InvalidProfileId),
+      tab_contents_(NULL),
+      note_(NULL),
+      reverted_(false) {
+}
+
+void LocaleChangeGuard::RevertLocaleChange(const ListValue* list) {
+  reverted_ = true;
+  UserMetrics::RecordAction(UserMetricsAction("LanguageChange_Revert"));
+  tab_contents_->profile()->ChangeApplicationLocale(from_locale_, true);
+  PrefService* prefs = tab_contents_->profile()->GetPrefs();
+  if (prefs) {
+    prefs->SetString(prefs::kApplicationLocaleBackup, from_locale_);
+    prefs->ClearPref(prefs::kApplicationLocaleAccepted);
+    prefs->ScheduleSavePersistentPrefs();
+  }
+  Browser* browser = Browser::GetBrowserForController(
+      &tab_contents_->controller(), NULL);
+  if (browser)
+    browser->ExecuteCommand(IDC_EXIT);
+}
+
+void LocaleChangeGuard::CheckLocaleChange(TabContents* tab_contents) {
+  // We want notification to be shown no more than once per session.
+  if (note_ != NULL)
+    return;
+  // We check profile Id because:
+  // (1) we want to exit fast in common case when nothing should be done.
+  // (2) on ChromeOS this guard may be invoked for a dummy profile first time.
+  ProfileId cur_profile_id = tab_contents->profile()->GetRuntimeId();
+  if (cur_profile_id == profile_id_)
+    return;
+  profile_id_ = cur_profile_id;
+  std::string cur_locale = g_browser_process->GetApplicationLocale();
+  if (cur_locale.empty())
+    return;
+  PrefService* prefs = tab_contents->profile()->GetPrefs();
+  if (prefs == NULL)
+    return;
+  to_locale_ = prefs->GetString(prefs::kApplicationLocaleOverride);
+  if (!to_locale_.empty()) {
+    DCHECK(to_locale_ == cur_locale);
+    return;
+  }
+  to_locale_ = prefs->GetString(prefs::kApplicationLocale);
+  if (to_locale_ != cur_locale)
+    return;
+  from_locale_ = prefs->GetString(prefs::kApplicationLocaleBackup);
+  if (from_locale_.empty() || from_locale_ == to_locale_)
+    return;
+  note_.reset(new chromeos::SystemNotification(
+      tab_contents->profile(),
+      new Delegate(this),
+      IDR_DEFAULT_FAVICON,
+      l10n_util::GetStringUTF16(
+          IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE)));
+  tab_contents_ = tab_contents;
+  note_->Show(
+      l10n_util::GetStringFUTF16(
+          IDS_LOCALE_CHANGE_MESSAGE,
+          l10n_util::GetDisplayNameForLocale(from_locale_, to_locale_, true),
+          l10n_util::GetDisplayNameForLocale(to_locale_, to_locale_, true)),
+      l10n_util::GetStringUTF16(IDS_LOCALE_CHANGE_REVERT_MESSAGE),
+      NewCallback(this, &LocaleChangeGuard::RevertLocaleChange),
+      true,  // urgent
+      false);  // non-sticky
+}
+
+void LocaleChangeGuard::AcceptLocaleChange() {
+  // Check whether locale has been reverted or changed.
+  // If not: mark current locale as accepted.
+  if (tab_contents_ == NULL)
+    return;
+  if (reverted_)
+    return;
+  PrefService* prefs = tab_contents_->profile()->GetPrefs();
+  if (prefs == NULL)
+    return;
+  std::string override_locale =
+      prefs->GetString(prefs::kApplicationLocaleOverride);
+  if (!override_locale.empty())
+    return;
+  if (prefs->GetString(prefs::kApplicationLocale) != to_locale_)
+    return;
+  UserMetrics::RecordAction(UserMetricsAction("LanguageChange_Accept"));
+  prefs->SetString(prefs::kApplicationLocaleBackup, to_locale_);
+  prefs->SetString(prefs::kApplicationLocaleAccepted, to_locale_);
+  prefs->ScheduleSavePersistentPrefs();
+}
+
+// static
+void LocaleChangeGuard::Check(TabContents* tab_contents) {
+  g_locale_change_guard.Get().CheckLocaleChange(tab_contents);
+}
+
+void LocaleChangeGuard::Delegate::Close(bool by_user) {
+  if (by_user)
+    master_->AcceptLocaleChange();
+}
+
+std::string LocaleChangeGuard::Delegate::id() const {
+  // Arbitrary unique Id.
+  return "8c386938-1e3f-11e0-ac7b-18a90520e2e5";
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/locale_change_guard.h b/chrome/browser/chromeos/locale_change_guard.h
new file mode 100644
index 0000000..ed6fa430
--- /dev/null
+++ b/chrome/browser/chromeos/locale_change_guard.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOCALE_CHANGE_GUARD_H_
+#define CHROME_BROWSER_CHROMEOS_LOCALE_CHANGE_GUARD_H_
+#pragma once
+
+#include "base/lazy_instance.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/notifications/system_notification.h"
+#include "chrome/browser/notifications/notification_delegate.h"
+#include "chrome/browser/profiles/profile.h"
+
+class ListValue;
+class TabContents;
+
+namespace chromeos {
+
+class LocaleChangeGuard {
+ public:
+  // When called first time for user profile: performs check whether
+  // locale has been changed automatically recently (based on synchronized user
+  // preference).  If so: shows notification that allows user to revert change.
+  // On subsequent calls: does nothing (hopefully fast).
+  static void Check(TabContents* tab_contents);
+
+ private:
+  class Delegate : public NotificationDelegate {
+   public:
+    explicit Delegate(chromeos::LocaleChangeGuard* master) : master_(master) {}
+    void Close(bool by_user);
+    void Display() {}
+    void Error() {}
+    void Click() {}
+    std::string id() const;
+
+   private:
+    chromeos::LocaleChangeGuard* master_;
+
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
+  LocaleChangeGuard();
+  void CheckLocaleChange(TabContents* tab_contents);
+  void RevertLocaleChange(const ListValue* list);
+  void AcceptLocaleChange();
+
+  std::string from_locale_;
+  std::string to_locale_;
+  ProfileId profile_id_;
+  TabContents* tab_contents_;
+  scoped_ptr<chromeos::SystemNotification> note_;
+  bool reverted_;
+
+  friend struct base::DefaultLazyInstanceTraits<LocaleChangeGuard>;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOCALE_CHANGE_GUARD_H_
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index 708f2e4b..7eb48ba 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -329,26 +329,53 @@
   }
 }
 
-void LoginUtilsImpl::RespectLocalePreference(PrefService* pref) {
-  std::string pref_locale = pref->GetString(prefs::kApplicationLocale);
-  if (pref_locale.empty()) {
-    // Profile synchronization takes time and is not completed at that moment
-    // at first login.  So we initialize locale preference in steps:
-    // (1) first save it to temporary backup;
-    // (2) on next login we assume that synchronization is already completed
-    //     and we may finalize initialization.
-    std::string pref_locale_backup =
-        pref->GetString(prefs::kApplicationLocaleBackup);
-    if (pref_locale_backup.empty()) {
-      pref->SetString(prefs::kApplicationLocaleBackup,
-                      g_browser_process->GetApplicationLocale());
-      return;
-    } else {
-      pref_locale.swap(pref_locale_backup);
-      pref->SetString(prefs::kApplicationLocale, pref_locale);
-    }
+void LoginUtilsImpl::RespectLocalePreference(PrefService* prefs) {
+  DCHECK(prefs != NULL);
+  std::string pref_locale_override =
+      prefs->GetString(prefs::kApplicationLocaleOverride);
+  if (!pref_locale_override.empty()) {
+    LanguageSwitchMenu::SwitchLanguage(pref_locale_override);
+    return;
   }
-  LanguageSwitchMenu::SwitchLanguage(pref_locale);
+
+  if (g_browser_process == NULL)
+    return;
+  std::string cur_locale = g_browser_process->GetApplicationLocale();
+
+  std::string pref_locale = prefs->GetString(prefs::kApplicationLocale);
+  if (!pref_locale.empty()) {
+    if (prefs->GetString(prefs::kApplicationLocaleAccepted) == pref_locale) {
+      // If locale is accepted then we do not want to show LocaleChange
+      // notification.  This notification is triggered by different values of
+      // kApplicationLocaleBackup and kApplicationLocale preferences,
+      // so make them identical.
+      prefs->SetString(prefs::kApplicationLocaleBackup, pref_locale);
+    } else {
+      std::string pref_locale_backup =
+          prefs->GetString(prefs::kApplicationLocaleBackup);
+      if (pref_locale_backup != cur_locale) {
+        if (pref_locale_backup == pref_locale || pref_locale_backup.empty()) {
+          prefs->SetString(prefs::kApplicationLocaleBackup, cur_locale);
+        }
+      }
+    }
+    LanguageSwitchMenu::SwitchLanguage(pref_locale);
+    return;
+  }
+  // Profile synchronization takes time and is not completed at that moment
+  // at first login.  So we initialize locale preference in steps:
+  // (1) first save it to temporary backup;
+  // (2) on next login we assume that synchronization is already completed
+  //     and we may finalize initialization.
+  std::string pref_locale_backup =
+      prefs->GetString(prefs::kApplicationLocaleBackup);
+  prefs->SetString(prefs::kApplicationLocaleBackup, cur_locale);
+  prefs->ScheduleSavePersistentPrefs();
+  if (!pref_locale_backup.empty()) {
+    prefs->SetString(prefs::kApplicationLocale, pref_locale_backup);
+    prefs->ScheduleSavePersistentPrefs();
+    LanguageSwitchMenu::SwitchLanguage(pref_locale_backup);
+  }
 }
 
 void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
diff --git a/chrome/browser/chromeos/notifications/system_notification.cc b/chrome/browser/chromeos/notifications/system_notification.cc
index 0d85687..42c46d1a 100644
--- a/chrome/browser/chromeos/notifications/system_notification.cc
+++ b/chrome/browser/chromeos/notifications/system_notification.cc
@@ -13,21 +13,39 @@
 
 namespace chromeos {
 
+void SystemNotification::Init(int icon_resource_id) {
+  collection_ = static_cast<BalloonCollectionImpl*>(
+       g_browser_process->notification_ui_manager()->balloon_collection());
+  std::string url = dom_ui_util::GetImageDataUrlFromResource(icon_resource_id);
+  DCHECK(!url.empty());
+  GURL tmp_gurl(url);
+  icon_.Swap(&tmp_gurl);
+}
+
+SystemNotification::SystemNotification(Profile* profile,
+                                       NotificationDelegate* delegate,
+                                       int icon_resource_id,
+                                       const string16& title)
+    : profile_(profile),
+      collection_(NULL),
+      delegate_(delegate),
+      title_(title),
+      visible_(false),
+      urgent_(false) {
+  Init(icon_resource_id);
+}
+
 SystemNotification::SystemNotification(Profile* profile,
                                        const std::string& id,
                                        int icon_resource_id,
                                        const string16& title)
     : profile_(profile),
-      collection_(static_cast<BalloonCollectionImpl*>(
-          g_browser_process->notification_ui_manager()->balloon_collection())),
+      collection_(NULL),
       delegate_(new Delegate(id)),
       title_(title),
       visible_(false),
       urgent_(false) {
-  std::string url = dom_ui_util::GetImageDataUrlFromResource(icon_resource_id);
-  DCHECK(!url.empty());
-  GURL tmp_gurl(url);
-  icon_.Swap(&tmp_gurl);
+  Init(icon_resource_id);
 }
 
 SystemNotification::~SystemNotification() {
diff --git a/chrome/browser/chromeos/notifications/system_notification.h b/chrome/browser/chromeos/notifications/system_notification.h
index 81976b771..5573f2b 100644
--- a/chrome/browser/chromeos/notifications/system_notification.h
+++ b/chrome/browser/chromeos/notifications/system_notification.h
@@ -27,7 +27,14 @@
   // The profile is the current user profile. The id is any string used
   // to uniquely identify this notification. The title is the title of
   // the message to be displayed. On creation, the message is hidden.
-  SystemNotification(Profile* profile, const std::string& id,
+  SystemNotification(Profile* profile,
+                     const std::string& id,
+                     int icon_resource_id,
+                     const string16& title);
+
+  // Allows to provide custom NotificationDelegate.
+  SystemNotification(Profile* profile,
+                     NotificationDelegate* delegate,
                      int icon_resource_id,
                      const string16& title);
 
@@ -71,9 +78,11 @@
     DISALLOW_COPY_AND_ASSIGN(Delegate);
   };
 
+  void Init(int icon_resource_id);
+
   Profile* profile_;
   BalloonCollectionImpl* collection_;
-  scoped_refptr<Delegate> delegate_;
+  scoped_refptr<NotificationDelegate> delegate_;
   GURL icon_;
   string16 title_;
   bool visible_;
diff --git a/chrome/browser/notifications/notification_ui_manager.h b/chrome/browser/notifications/notification_ui_manager.h
index 3a0125c3..1b9475df 100644
--- a/chrome/browser/notifications/notification_ui_manager.h
+++ b/chrome/browser/notifications/notification_ui_manager.h
@@ -73,12 +73,12 @@
   // be placed on the screen.
   void SetPositionPreference(BalloonCollection::PositionPreference preference);
 
-  // NotificationObserver interface (the event signaling kind of notifications)
+ private:
+  // NotificationObserver override.
   virtual void Observe(NotificationType type,
                        const NotificationSource& source,
                        const NotificationDetails& details);
 
- private:
   // Attempts to display notifications from the show_queue if the user
   // is active.
   void CheckAndShowNotifications();
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 6705e3b..658face 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -112,6 +112,8 @@
   // in user's profile for other platforms as well.
   prefs->RegisterStringPref(prefs::kApplicationLocale, "");
   prefs->RegisterStringPref(prefs::kApplicationLocaleBackup, "");
+  prefs->RegisterStringPref(prefs::kApplicationLocaleOverride, "");
+  prefs->RegisterStringPref(prefs::kApplicationLocaleAccepted, "");
 #endif
 }
 
@@ -603,6 +605,12 @@
     return NULL;
   }
 
+#if defined(OS_CHROMEOS)
+  virtual void ChangeApplicationLocale(
+      const std::string& locale, bool keep_local) {
+  }
+#endif  // defined(OS_CHROMEOS)
+
   virtual PrefProxyConfigTracker* GetProxyConfigTracker() {
     return profile_->GetProxyConfigTracker();
   }
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 9df977c..db2f266 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -226,8 +226,7 @@
   // Retrieves a pointer to the TransportSecurityState associated with
   // this profile.  The TransportSecurityState is lazily created the
   // first time that this method is called.
-  virtual net::TransportSecurityState*
-      GetTransportSecurityState() = 0;
+  virtual net::TransportSecurityState* GetTransportSecurityState() = 0;
 
   // Retrieves a pointer to the FaviconService associated with this
   // profile.  The FaviconService is lazily created the first time
@@ -487,6 +486,11 @@
   virtual policy::ProfilePolicyContext* GetPolicyContext() = 0;
 
 #if defined(OS_CHROMEOS)
+  // Changes application locale.
+  // "Keep local" means that changes should not be propagated to other devices.
+  virtual void ChangeApplicationLocale(
+      const std::string& locale, bool keep_local) = 0;
+
   // Returns ChromeOS's ProxyConfigServiceImpl, creating if not yet created.
   virtual chromeos::ProxyConfigServiceImpl*
       GetChromeOSProxyConfigServiceImpl() = 0;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index d4f24d8..4a60cd11 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -1340,6 +1340,30 @@
 }
 
 #if defined(OS_CHROMEOS)
+void ProfileImpl::ChangeApplicationLocale(
+    const std::string& locale, bool keep_local) {
+  if (locale.empty()) {
+    NOTREACHED();
+    return;
+  }
+  if (keep_local) {
+    GetPrefs()->SetString(prefs::kApplicationLocaleOverride, locale);
+  } else {
+    GetPrefs()->SetString(prefs::kApplicationLocale, locale);
+    GetPrefs()->SetString(prefs::kApplicationLocaleOverride, "");
+  }
+  GetPrefs()->SetString(prefs::kApplicationLocaleBackup, locale);
+  GetPrefs()->ClearPref(prefs::kApplicationLocaleAccepted);
+  // We maintain kApplicationLocale property in both a global storage
+  // and user's profile.  Global property determines locale of login screen,
+  // while user's profile determines his personal locale preference.
+  g_browser_process->local_state()->SetString(
+      prefs::kApplicationLocale, locale);
+
+  GetPrefs()->SavePersistentPrefs();
+  g_browser_process->local_state()->SavePersistentPrefs();
+}
+
 chromeos::ProxyConfigServiceImpl*
     ProfileImpl::GetChromeOSProxyConfigServiceImpl() {
   if (!chromeos_proxy_config_service_impl_) {
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index bc5f790..3f9e53c5 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -129,6 +129,8 @@
   virtual policy::ProfilePolicyContext* GetPolicyContext();
 
 #if defined(OS_CHROMEOS)
+  virtual void ChangeApplicationLocale(
+      const std::string& locale, bool keep_local);
   virtual chromeos::ProxyConfigServiceImpl* GetChromeOSProxyConfigServiceImpl();
   virtual void SetupChromeOSEnterpriseExtensionObserver();
 #endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/tab_contents/infobar_delegate.h b/chrome/browser/tab_contents/infobar_delegate.h
index af9b9c9..c48d82b2 100644
--- a/chrome/browser/tab_contents/infobar_delegate.h
+++ b/chrome/browser/tab_contents/infobar_delegate.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -190,11 +190,11 @@
 class ConfirmInfoBarDelegate : public AlertInfoBarDelegate {
  public:
   enum InfoBarButton {
-    BUTTON_NONE = 0,
-    BUTTON_OK = 1,
-    BUTTON_CANCEL = 2,
+    BUTTON_NONE       = 0,
+    BUTTON_OK         = 1 << 0,
+    BUTTON_CANCEL     = 1 << 1,
     // Specifies that the OK button should be rendered like a default button.
-    BUTTON_OK_DEFAULT = 4
+    BUTTON_OK_DEFAULT = 1 << 2
   };
 
   // Return the buttons to be shown for this InfoBar.
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 32bd04c2..4701265 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -111,6 +111,10 @@
 #include "app/surface/io_surface_support_mac.h"
 #endif  // defined(OS_MACOSX)
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/locale_change_guard.h"
+#endif  // defined(OS_CHROMEOS)
+
 // Cross-Site Navigations
 //
 // If a TabContents is told to navigate to a different web site (as determined
@@ -843,6 +847,9 @@
 
   WebCacheManager::GetInstance()->ObserveActivity(GetRenderProcessHost()->id());
   last_selected_time_ = base::TimeTicks::Now();
+#if defined(OS_CHROMEOS)
+  chromeos::LocaleChangeGuard::Check(this);
+#endif
 }
 
 void TabContents::FadeForInstant(bool animate) {
@@ -1996,9 +2003,8 @@
   // Clear out any constrained windows since we are leaving this page entirely.
   // We use indices instead of iterators in case CloseWindow does something
   // that may invalidate an iterator.
-  int size = static_cast<int>(child_windows_.size());
-  for (int i = size - 1; i >= 0; --i) {
-    ConstrainedWindow* window = child_windows_[i];
+  for (size_t i = 0; i < child_windows_.size(); ++i) {
+    ConstrainedWindow* window = child_windows_[child_windows_.size() - 1 - i];
     if (window) {
       window->CloseConstrainedWindow();
       BlockTabContent(false);
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 5917cbc..c65ba62 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -389,18 +389,6 @@
         'browser/chrome_plugin_browsing_context.h',
         'browser/chrome_plugin_host.cc',
         'browser/chrome_plugin_host.h',
-        'browser/chromeos/notifications/balloon_collection_impl.cc',
-        'browser/chromeos/notifications/balloon_collection_impl.h',
-        'browser/chromeos/notifications/balloon_view.cc',
-        'browser/chromeos/notifications/balloon_view.h',
-        'browser/chromeos/notifications/balloon_view_host.cc',
-        'browser/chromeos/notifications/balloon_view_host.h',
-        'browser/chromeos/notifications/notification_panel.cc',
-        'browser/chromeos/notifications/notification_panel.h',
-        'browser/chromeos/notifications/system_notification.cc',
-        'browser/chromeos/notifications/system_notification.h',
-        'browser/chromeos/notifications/system_notification_factory.cc',
-        'browser/chromeos/notifications/system_notification_factory.h',
         'browser/chromeos/audio_handler.cc',
         'browser/chromeos/audio_handler.h',
         'browser/chromeos/audio_mixer.h',
@@ -545,6 +533,8 @@
         'browser/chromeos/input_method/input_method_util.h',
         'browser/chromeos/language_preferences.cc',
         'browser/chromeos/language_preferences.h',
+        'browser/chromeos/locale_change_guard.h',
+        'browser/chromeos/locale_change_guard.cc',
         'browser/chromeos/login/account_creation_view.cc',
         'browser/chromeos/login/account_creation_view.h',
         'browser/chromeos/login/account_screen.cc',
@@ -697,6 +687,18 @@
         'browser/chromeos/network_state_notifier.h',
         'browser/chromeos/network_message_observer.cc',
         'browser/chromeos/network_message_observer.h',
+        'browser/chromeos/notifications/balloon_collection_impl.cc',
+        'browser/chromeos/notifications/balloon_collection_impl.h',
+        'browser/chromeos/notifications/balloon_view.cc',
+        'browser/chromeos/notifications/balloon_view.h',
+        'browser/chromeos/notifications/balloon_view_host.cc',
+        'browser/chromeos/notifications/balloon_view_host.h',
+        'browser/chromeos/notifications/notification_panel.cc',
+        'browser/chromeos/notifications/notification_panel.h',
+        'browser/chromeos/notifications/system_notification.cc',
+        'browser/chromeos/notifications/system_notification.h',
+        'browser/chromeos/notifications/system_notification_factory.cc',
+        'browser/chromeos/notifications/system_notification_factory.h',
         'browser/chromeos/offline/offline_load_page.cc',
         'browser/chromeos/offline/offline_load_page.h',
         'browser/chromeos/offline/offline_load_service.cc',
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index f81ffde..38126e0 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -46,9 +46,16 @@
 // while user's profile determines his personal locale preference.
 const char kApplicationLocale[] = "intl.app_locale";
 #if defined(OS_CHROMEOS)
-// Non-syncable item.  Used for two-step initialization of locale in ChromeOS
+// Non-syncable item.  Used to detect locale change.
+// Used for two-step initialization of locale in ChromeOS
 // because synchronization of kApplicationLocale is not instant.
 const char kApplicationLocaleBackup[] = "intl.app_locale_backup";
+// Non-syncable item.
+// Used to locally override synchronized kApplicationLocale preference.
+const char kApplicationLocaleOverride[] = "intl.app_locale_override";
+// Locale accepted by user.  Non-syncable.
+// Used to determine whether we need to show Locale Change notification.
+const char kApplicationLocaleAccepted[] = "intl.app_locale_accepted";
 #endif
 
 // The default character encoding to assume for a web page in the
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 09ee43ee..1963bf61 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -27,6 +27,8 @@
 extern const char kApplicationLocale[];
 #if defined(OS_CHROMEOS)
 extern const char kApplicationLocaleBackup[];
+extern const char kApplicationLocaleOverride[];
+extern const char kApplicationLocaleAccepted[];
 #endif
 
 extern const char kDefaultCharset[];
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 847093e..181e3753 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -298,6 +298,8 @@
   }
   virtual void SetupChromeOSEnterpriseExtensionObserver() {
   }
+  virtual void ChangeApplicationLocale(const std::string&, bool) {
+  }
 #endif  // defined(OS_CHROMEOS)
 
   virtual PrefProxyConfigTracker* GetProxyConfigTracker();
diff --git a/chrome/tools/chromeactions.txt b/chrome/tools/chromeactions.txt
index c0a80df6..c91b877 100644
--- a/chrome/tools/chromeactions.txt
+++ b/chrome/tools/chromeactions.txt
@@ -13,6 +13,7 @@
 0x307b8a127f85947e	AboutFlags_expose-for-tabs
 0x2c97f94b6aca4a22	AboutFlags_extension-apis
 0x66a2e456dfe783d3	AboutFlags_gpu-canvas-2d
+0x6cb0582a680ffec6	AboutFlags_instant-autocomplete-immediately
 0x67b7031bb00a6917	AboutFlags_instant-type
 0x681dbf08b11af420	AboutFlags_match-preview
 0x0156f26c1be32122	AboutFlags_my-special-feature
@@ -174,6 +175,7 @@
 0xd477cbce1681d404	CloseTab_Mouse
 0x4b31de70a21d7903	CloseWebApp
 0xdf8926d323575ff8	CloseWindow
+0xa0ebbbdb0eca8d89	ConflictBadge
 0x5fb63579fc981698	Copy
 0xb3d0f42456c6eaf6	CopyURLToClipBoard
 0x2aeb39c03cc86464	CreateLink
@@ -379,6 +381,8 @@
 0x204aad0f4a1f0f22	KeywordEditor_AddKeywordJS
 0x37ac83353fd9be1f	KeywordEditor_ModifiedKeyword
 0x2d038477eb20483b	KeywordEditor_RemoveKeyword
+0xab20f097361154dc	LanguageChange_Accept
+0x98ee7b2a2893443f	LanguageChange_Revert
 0xcce20fb4bce11250	LanguageConfigView_Open
 0x6c9d4656451fe020	LanguageMenuButton_InputMethodChanged
 0x9895b811fa1a2f7e	LanguageMenuButton_Open