Commit e49cf56c authored by Evan Stade's avatar Evan Stade Committed by Commit Bot

WebLayer: handle locale changes and multiple locales

Set ACCEPT_LANGUAGES based on the entire locale list, rather than
just the top locale. It also updates ACCEPT_LANGUAGES when the
list changes, rather than just once at startup.

Navigator.language and .languages are likewise updated.

The ResourceBundle now loads new strings as well, although WebLayer
only packs English strings at the moment.

Bug: 1025064
Change-Id: I18997eb20c883a976edf624c0a5f45b5f012aff3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1924722
Commit-Queue: Evan Stade <estade@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Reviewed-by: default avatarClark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718508}
parent feb784c7
...@@ -201,6 +201,7 @@ public class LocaleUtils { ...@@ -201,6 +201,7 @@ public class LocaleUtils {
* Each language tag is well-formed IETF BCP 47 language tag with language and country * Each language tag is well-formed IETF BCP 47 language tag with language and country
* code. * code.
*/ */
@CalledByNative
public static String getDefaultLocaleListString() { public static String getDefaultLocaleListString() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return toLanguageTags(LocaleList.getDefault()); return toLanguageTags(LocaleList.getDefault());
......
...@@ -23,5 +23,12 @@ std::string GetDefaultLocaleString() { ...@@ -23,5 +23,12 @@ std::string GetDefaultLocaleString() {
return ConvertJavaStringToUTF8(locale); return ConvertJavaStringToUTF8(locale);
} }
std::string GetDefaultLocaleListString() {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jstring> locales =
Java_LocaleUtils_getDefaultLocaleListString(env);
return ConvertJavaStringToUTF8(locales);
}
} // namespace android } // namespace android
} // namespace base } // namespace base
...@@ -19,6 +19,10 @@ BASE_EXPORT std::string GetDefaultCountryCode(); ...@@ -19,6 +19,10 @@ BASE_EXPORT std::string GetDefaultCountryCode();
// Return the current default locale of the device as string. // Return the current default locale of the device as string.
BASE_EXPORT std::string GetDefaultLocaleString(); BASE_EXPORT std::string GetDefaultLocaleString();
// Returns a list of user-selected locales as a comma separated string, ordered
// by decreasing preference.
BASE_EXPORT std::string GetDefaultLocaleListString();
} // namespace android } // namespace android
} // namespace base } // namespace base
......
...@@ -108,10 +108,6 @@ std::string ResourceBundle::LoadLocaleResources( ...@@ -108,10 +108,6 @@ std::string ResourceBundle::LoadLocaleResources(
DCHECK(!locale_resources_data_.get() && DCHECK(!locale_resources_data_.get() &&
!secondary_locale_resources_data_.get()) !secondary_locale_resources_data_.get())
<< "locale.pak already loaded"; << "locale.pak already loaded";
if (g_locale_pack_fd != -1) {
LOG(WARNING)
<< "Unexpected (outside of tests): Loading a second locale pak file.";
}
std::string app_locale = l10n_util::GetApplicationLocale(pref_locale); std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
// Some Chromium apps have two sets of .pak files for their UI strings, i.e.: // Some Chromium apps have two sets of .pak files for their UI strings, i.e.:
......
...@@ -5,8 +5,26 @@ ...@@ -5,8 +5,26 @@
#include "weblayer/browser/i18n_util.h" #include "weblayer/browser/i18n_util.h"
#include "base/i18n/rtl.h" #include "base/i18n/rtl.h"
#include "base/no_destructor.h"
#include "build/build_config.h"
#include "net/http/http_util.h" #include "net/http/http_util.h"
#if defined(OS_ANDROID)
#include "base/android/locale_utils.h"
#include "base/task/post_task.h"
#include "ui/base/resource/resource_bundle.h"
#include "weblayer/browser/java/jni/LocaleChangedBroadcastReceiver_jni.h"
#endif
namespace {
base::CallbackList<void()>& GetLocaleChangeCallbacks() {
static base::NoDestructor<base::CallbackList<void()>> instance;
return *instance;
}
} // namespace
namespace weblayer { namespace weblayer {
namespace i18n { namespace i18n {
...@@ -16,9 +34,35 @@ std::string GetApplicationLocale() { ...@@ -16,9 +34,35 @@ std::string GetApplicationLocale() {
} }
std::string GetAcceptLangs() { std::string GetAcceptLangs() {
// TODO(estade): return more languages, not just the default. #if defined(OS_ANDROID)
return net::HttpUtil::ExpandLanguageList(GetApplicationLocale()); std::string locale_list = base::android::GetDefaultLocaleListString();
#else
std::string locale_list = GetApplicationLocale();
#endif
return net::HttpUtil::ExpandLanguageList(locale_list);
}
std::unique_ptr<LocaleChangeSubscription> RegisterLocaleChangeCallback(
base::RepeatingClosure locale_changed) {
return GetLocaleChangeCallbacks().Add(locale_changed);
}
#if defined(OS_ANDROID)
static void JNI_LocaleChangedBroadcastReceiver_LocaleChanged(JNIEnv* env) {
base::PostTaskAndReply(
FROM_HERE,
{base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce([]() {
// Passing an empty |pref_locale| means the Android system locale will
// be used (base::android::GetDefaultLocaleString()).
ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources(
{} /*pref_locale*/);
}),
base::BindOnce([]() { GetLocaleChangeCallbacks().Notify(); }));
// TODO(estade): need to update the ResourceBundle for non-Browser processes
// as well.
} }
#endif
} // namespace i18n } // namespace i18n
} // namespace weblayer } // namespace weblayer
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include <string> #include <string>
#include "base/callback_list.h"
namespace weblayer { namespace weblayer {
namespace i18n { namespace i18n {
...@@ -17,6 +19,11 @@ std::string GetApplicationLocale(); ...@@ -17,6 +19,11 @@ std::string GetApplicationLocale();
// This may be called on any thread. // This may be called on any thread.
std::string GetAcceptLangs(); std::string GetAcceptLangs();
using LocaleChangeSubscription = base::CallbackList<void()>::Subscription;
std::unique_ptr<LocaleChangeSubscription> RegisterLocaleChangeCallback(
base::RepeatingClosure locale_changed);
} // namespace i18n } // namespace i18n
} // namespace weblayer } // namespace weblayer
......
...@@ -35,6 +35,7 @@ android_library("java") { ...@@ -35,6 +35,7 @@ android_library("java") {
"org/chromium/weblayer_private/ErrorPageCallbackProxy.java", "org/chromium/weblayer_private/ErrorPageCallbackProxy.java",
"org/chromium/weblayer_private/ActionModeCallback.java", "org/chromium/weblayer_private/ActionModeCallback.java",
"org/chromium/weblayer_private/FullscreenCallbackProxy.java", "org/chromium/weblayer_private/FullscreenCallbackProxy.java",
"org/chromium/weblayer_private/LocaleChangedBroadcastReceiver.java",
"org/chromium/weblayer_private/NavigationControllerImpl.java", "org/chromium/weblayer_private/NavigationControllerImpl.java",
"org/chromium/weblayer_private/NavigationImpl.java", "org/chromium/weblayer_private/NavigationImpl.java",
"org/chromium/weblayer_private/NewTabCallbackProxy.java", "org/chromium/weblayer_private/NewTabCallbackProxy.java",
...@@ -83,6 +84,7 @@ generate_jni("jni") { ...@@ -83,6 +84,7 @@ generate_jni("jni") {
"org/chromium/weblayer_private/DownloadCallbackProxy.java", "org/chromium/weblayer_private/DownloadCallbackProxy.java",
"org/chromium/weblayer_private/ErrorPageCallbackProxy.java", "org/chromium/weblayer_private/ErrorPageCallbackProxy.java",
"org/chromium/weblayer_private/FullscreenCallbackProxy.java", "org/chromium/weblayer_private/FullscreenCallbackProxy.java",
"org/chromium/weblayer_private/LocaleChangedBroadcastReceiver.java",
"org/chromium/weblayer_private/NavigationControllerImpl.java", "org/chromium/weblayer_private/NavigationControllerImpl.java",
"org/chromium/weblayer_private/NavigationImpl.java", "org/chromium/weblayer_private/NavigationImpl.java",
"org/chromium/weblayer_private/NewTabCallbackProxy.java", "org/chromium/weblayer_private/NewTabCallbackProxy.java",
......
...@@ -34,6 +34,7 @@ public class BrowserImpl extends IBrowser.Stub { ...@@ -34,6 +34,7 @@ public class BrowserImpl extends IBrowser.Stub {
private FragmentWindowAndroid mWindowAndroid; private FragmentWindowAndroid mWindowAndroid;
private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>(); private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
private IBrowserClient mClient; private IBrowserClient mClient;
private LocaleChangedBroadcastReceiver mLocaleReceiver;
public BrowserImpl(ProfileImpl profile, Bundle savedInstanceState) { public BrowserImpl(ProfileImpl profile, Bundle savedInstanceState) {
mProfile = profile; mProfile = profile;
...@@ -55,6 +56,8 @@ public class BrowserImpl extends IBrowser.Stub { ...@@ -55,6 +56,8 @@ public class BrowserImpl extends IBrowser.Stub {
addTab(tab); addTab(tab);
boolean set_active_result = setActiveTab(tab); boolean set_active_result = setActiveTab(tab);
assert set_active_result; assert set_active_result;
mLocaleReceiver = new LocaleChangedBroadcastReceiver(context);
} }
public void onFragmentDetached() { public void onFragmentDetached() {
...@@ -187,6 +190,10 @@ public class BrowserImpl extends IBrowser.Stub { ...@@ -187,6 +190,10 @@ public class BrowserImpl extends IBrowser.Stub {
} }
public void destroy() { public void destroy() {
if (mLocaleReceiver != null) {
mLocaleReceiver.destroy();
mLocaleReceiver = null;
}
if (mViewController != null) { if (mViewController != null) {
mViewController.destroy(); mViewController.destroy();
for (TabImpl tab : mTabs) { for (TabImpl tab : mTabs) {
......
// Copyright 2019 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.
package org.chromium.weblayer_private;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
/**
* Triggered when Android's locale changes.
*/
@JNINamespace("weblayer::i18n")
public class LocaleChangedBroadcastReceiver extends BroadcastReceiver {
private final Context mContext;
public LocaleChangedBroadcastReceiver(Context context) {
mContext = context;
mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
}
public void destroy() {
mContext.unregisterReceiver(this);
}
@Override
public void onReceive(Context context, Intent intent) {
if (!Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) return;
LocaleChangedBroadcastReceiverJni.get().localeChanged();
}
@NativeMethods
interface Natives {
void localeChanged();
}
}
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/download_manager_delegate.h" #include "content/public/browser/download_manager_delegate.h"
#include "content/public/browser/resource_context.h" #include "content/public/browser/resource_context.h"
#include "content/public/browser/storage_partition.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "weblayer/browser/ssl_host_state_delegate_impl.h" #include "weblayer/browser/ssl_host_state_delegate_impl.h"
#include "weblayer/browser/tab_impl.h" #include "weblayer/browser/tab_impl.h"
#include "weblayer/common/weblayer_paths.h" #include "weblayer/common/weblayer_paths.h"
...@@ -225,6 +227,9 @@ ProfileImpl::ProfileImpl(const std::string& name) { ...@@ -225,6 +227,9 @@ ProfileImpl::ProfileImpl(const std::string& name) {
web_cache::WebCacheManager::GetInstance(); web_cache::WebCacheManager::GetInstance();
browser_context_ = std::make_unique<BrowserContextImpl>(path); browser_context_ = std::make_unique<BrowserContextImpl>(path);
locale_change_subscription_ = i18n::RegisterLocaleChangeCallback(
base::Bind(&ProfileImpl::OnLocaleChanged, base::Unretained(this)));
} }
ProfileImpl::~ProfileImpl() { ProfileImpl::~ProfileImpl() {
...@@ -279,6 +284,18 @@ void ProfileImpl::ClearRendererCache() { ...@@ -279,6 +284,18 @@ void ProfileImpl::ClearRendererCache() {
} }
} }
void ProfileImpl::OnLocaleChanged() {
content::BrowserContext::ForEachStoragePartition(
GetBrowserContext(),
base::BindRepeating(
[](const std::string& accept_language,
content::StoragePartition* storage_partition) {
storage_partition->GetNetworkContext()->SetAcceptLanguage(
accept_language);
},
i18n::GetAcceptLangs()));
}
std::unique_ptr<Profile> Profile::Create(const std::string& name) { std::unique_ptr<Profile> Profile::Create(const std::string& name) {
return std::make_unique<ProfileImpl>(name); return std::make_unique<ProfileImpl>(name);
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "weblayer/browser/i18n_util.h"
#include "weblayer/public/profile.h" #include "weblayer/public/profile.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -51,8 +52,13 @@ class ProfileImpl : public Profile { ...@@ -51,8 +52,13 @@ class ProfileImpl : public Profile {
void ClearRendererCache(); void ClearRendererCache();
// Callback when the system locale has been updated.
void OnLocaleChanged();
std::unique_ptr<BrowserContextImpl> browser_context_; std::unique_ptr<BrowserContextImpl> browser_context_;
std::unique_ptr<i18n::LocaleChangeSubscription> locale_change_subscription_;
DISALLOW_COPY_AND_ASSIGN(ProfileImpl); DISALLOW_COPY_AND_ASSIGN(ProfileImpl);
}; };
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "third_party/blink/public/mojom/renderer_preferences.mojom.h" #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
#include "ui/base/window_open_disposition.h" #include "ui/base/window_open_disposition.h"
#include "weblayer/browser/file_select_helper.h" #include "weblayer/browser/file_select_helper.h"
#include "weblayer/browser/i18n_util.h"
#include "weblayer/browser/isolated_world_ids.h" #include "weblayer/browser/isolated_world_ids.h"
#include "weblayer/browser/navigation_controller_impl.h" #include "weblayer/browser/navigation_controller_impl.h"
#include "weblayer/browser/profile_impl.h" #include "weblayer/browser/profile_impl.h"
...@@ -110,10 +109,9 @@ TabImpl::TabImpl(ProfileImpl* profile, ...@@ -110,10 +109,9 @@ TabImpl::TabImpl(ProfileImpl* profile,
web_contents_ = content::WebContents::Create(create_params); web_contents_ = content::WebContents::Create(create_params);
} }
// TODO(estade): set more preferences, and set them dynamically rather than UpdateRendererPrefs(false);
// just at startup. locale_change_subscription_ = i18n::RegisterLocaleChangeCallback(
web_contents_->GetMutableRendererPrefs()->accept_languages = base::Bind(&TabImpl::UpdateRendererPrefs, base::Unretained(this), true));
i18n::GetAcceptLangs();
std::unique_ptr<UserData> user_data = std::make_unique<UserData>(); std::unique_ptr<UserData> user_data = std::make_unique<UserData>();
user_data->controller = this; user_data->controller = this;
...@@ -395,6 +393,13 @@ void TabImpl::OnExitFullscreen() { ...@@ -395,6 +393,13 @@ void TabImpl::OnExitFullscreen() {
web_contents_->ExitFullscreen(/* will_cause_resize */ false); web_contents_->ExitFullscreen(/* will_cause_resize */ false);
} }
void TabImpl::UpdateRendererPrefs(bool should_sync_prefs) {
web_contents_->GetMutableRendererPrefs()->accept_languages =
i18n::GetAcceptLangs();
if (should_sync_prefs)
web_contents_->SyncRendererPrefs();
}
std::unique_ptr<Tab> Tab::Create(Profile* profile) { std::unique_ptr<Tab> Tab::Create(Profile* profile) {
return std::make_unique<TabImpl>(static_cast<ProfileImpl*>(profile)); return std::make_unique<TabImpl>(static_cast<ProfileImpl*>(profile));
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "weblayer/browser/i18n_util.h"
#include "weblayer/public/tab.h" #include "weblayer/public/tab.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -133,6 +134,8 @@ class TabImpl : public Tab, ...@@ -133,6 +134,8 @@ class TabImpl : public Tab,
// Called from closure supplied to delegate to exit fullscreen. // Called from closure supplied to delegate to exit fullscreen.
void OnExitFullscreen(); void OnExitFullscreen();
void UpdateRendererPrefs(bool should_sync_prefs);
DownloadDelegate* download_delegate_ = nullptr; DownloadDelegate* download_delegate_ = nullptr;
ErrorPageDelegate* error_page_delegate_ = nullptr; ErrorPageDelegate* error_page_delegate_ = nullptr;
FullscreenDelegate* fullscreen_delegate_ = nullptr; FullscreenDelegate* fullscreen_delegate_ = nullptr;
...@@ -141,6 +144,7 @@ class TabImpl : public Tab, ...@@ -141,6 +144,7 @@ class TabImpl : public Tab,
std::unique_ptr<content::WebContents> web_contents_; std::unique_ptr<content::WebContents> web_contents_;
std::unique_ptr<NavigationControllerImpl> navigation_controller_; std::unique_ptr<NavigationControllerImpl> navigation_controller_;
base::ObserverList<TabObserver>::Unchecked observers_; base::ObserverList<TabObserver>::Unchecked observers_;
std::unique_ptr<i18n::LocaleChangeSubscription> locale_change_subscription_;
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
TopControlsContainerView* top_controls_container_view_ = nullptr; TopControlsContainerView* top_controls_container_view_ = nullptr;
base::android::ScopedJavaGlobalRef<jobject> java_impl_; base::android::ScopedJavaGlobalRef<jobject> java_impl_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment