Commit 80ec9a2d authored by Trevor Perrier's avatar Trevor Perrier Committed by Commit Bot

[Android] Add AppLocaleController for language decouple

This CL adds the AppLocaleController interface and the
GlobalAppLocaleController implementation which use the
APPLICATION_OVERRIDE_LANGUAGE value to override the Clank language.

Early in ChromeApplication.attachBaseContext the
GlobaleAppLocaleController singleton is initialized with the override
language and updates the Application level Locales/LocaleList.  Doing
the Application override this early also overrides the ContextUtils
wrapped application Context.

The base Context passed by Android to the Activity level
attachBaseContext still uses the system locales so an Activity level
locale override is also done.

The override language is used for CCTs.

This is the third of four CLs for this feature.  The next will
introduce the UI changes to allow users to control the preference.

Bug: 1068667
Change-Id: Ifbbe9f8ed592c1b890a9069ef5cbfb685d34e00f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2354546Reviewed-by: default avatarTrevor  Perrier <perrier@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarBrandon Wylie <wylieb@chromium.org>
Commit-Queue: Trevor  Perrier <perrier@chromium.org>
Cr-Commit-Position: refs/heads/master@{#805882}
parent 3cb21195
...@@ -881,6 +881,7 @@ chrome_java_sources = [ ...@@ -881,6 +881,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/invalidation/ResumableDelayedTaskRunner.java", "java/src/org/chromium/chrome/browser/invalidation/ResumableDelayedTaskRunner.java",
"java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java", "java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java",
"java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java", "java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java",
"java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java",
"java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java", "java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java",
"java/src/org/chromium/chrome/browser/language/settings/AddLanguageFragment.java", "java/src/org/chromium/chrome/browser/language/settings/AddLanguageFragment.java",
"java/src/org/chromium/chrome/browser/language/settings/LanguageItem.java", "java/src/org/chromium/chrome/browser/language/settings/LanguageItem.java",
......
...@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.dependency_injection.DaggerChromeAppComponent ...@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.dependency_injection.DaggerChromeAppComponent
import org.chromium.chrome.browser.dependency_injection.ModuleFactoryOverrides; import org.chromium.chrome.browser.dependency_injection.ModuleFactoryOverrides;
import org.chromium.chrome.browser.flags.CachedFeatureFlags; import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.language.GlobalAppLocaleController;
import org.chromium.chrome.browser.metrics.UmaUtils; import org.chromium.chrome.browser.metrics.UmaUtils;
import org.chromium.chrome.browser.night_mode.SystemNightModeMonitor; import org.chromium.chrome.browser.night_mode.SystemNightModeMonitor;
import org.chromium.chrome.browser.vr.OnExitVrRequestListener; import org.chromium.chrome.browser.vr.OnExitVrRequestListener;
...@@ -79,7 +80,19 @@ public class ChromeApplication extends Application { ...@@ -79,7 +80,19 @@ public class ChromeApplication extends Application {
@Override @Override
protected void attachBaseContext(Context context) { protected void attachBaseContext(Context context) {
boolean isBrowserProcess = isBrowserProcess(); boolean isBrowserProcess = isBrowserProcess();
if (isBrowserProcess) UmaUtils.recordMainEntryPointTime();
if (isBrowserProcess) {
UmaUtils.recordMainEntryPointTime();
// If the app locale override preference is set, create a new override
// context to use as the base context for the application.
// Must be initialized early to override Application level localizations.
if (GlobalAppLocaleController.getInstance().init(context)) {
context = context.createConfigurationContext(
GlobalAppLocaleController.getInstance().getOverrideConfig(context));
}
}
super.attachBaseContext(context); super.attachBaseContext(context);
ContextUtils.initApplicationContext(this); ContextUtils.initApplicationContext(this);
maybeInitProcessType(isBrowserProcess); maybeInitProcessType(isBrowserProcess);
......
...@@ -15,6 +15,7 @@ import androidx.annotation.StyleRes; ...@@ -15,6 +15,7 @@ import androidx.annotation.StyleRes;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.language.GlobalAppLocaleController;
import org.chromium.chrome.browser.night_mode.GlobalNightModeStateProviderHolder; import org.chromium.chrome.browser.night_mode.GlobalNightModeStateProviderHolder;
import org.chromium.chrome.browser.night_mode.NightModeStateProvider; import org.chromium.chrome.browser.night_mode.NightModeStateProvider;
import org.chromium.chrome.browser.night_mode.NightModeUtils; import org.chromium.chrome.browser.night_mode.NightModeUtils;
...@@ -77,8 +78,11 @@ public class ChromeBaseAppCompatActivity ...@@ -77,8 +78,11 @@ public class ChromeBaseAppCompatActivity
*/ */
@CallSuper @CallSuper
protected boolean applyOverrides(Context baseContext, Configuration overrideConfig) { protected boolean applyOverrides(Context baseContext, Configuration overrideConfig) {
return NightModeUtils.applyOverridesForNightMode( boolean applied = NightModeUtils.applyOverridesForNightMode(
getNightModeStateProvider(), overrideConfig); getNightModeStateProvider(), overrideConfig);
applied |= GlobalAppLocaleController.getInstance().applyActivityOverrides(
baseContext, overrideConfig);
return applied;
} }
/** /**
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.language; package org.chromium.chrome.browser.language;
import android.content.Context;
import android.preference.PreferenceManager;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.android.play.core.splitinstall.SplitInstallManager; import com.google.android.play.core.splitinstall.SplitInstallManager;
...@@ -35,13 +37,26 @@ public class AppLocaleUtils { ...@@ -35,13 +37,26 @@ public class AppLocaleUtils {
/** /**
* Get the value of application language shared preference or null if there is none. * Get the value of application language shared preference or null if there is none.
* @return String * @return String BCP-47 language tag (e.g. en-US).
*/ */
public static String getAppLanguagePref() { public static String getAppLanguagePref() {
return SharedPreferencesManager.getInstance().readString( return SharedPreferencesManager.getInstance().readString(
ChromePreferenceKeys.APPLICATION_OVERRIDE_LANGUAGE, null); ChromePreferenceKeys.APPLICATION_OVERRIDE_LANGUAGE, null);
} }
/**
* Get the value of application language shared preference or null if there is none.
* Used during {@link ChromeApplication#attachBaseContext} before
* {@link SharedPreferencesManager} is created.
* @param base Context to use for getting the shared preference.
* @return String BCP-47 language tag (e.g. en-US).
*/
@SuppressWarnings("DefaultSharedPreferencesCheck")
protected static String getAppLanguagePrefStartUp(Context base) {
return PreferenceManager.getDefaultSharedPreferences(base).getString(
ChromePreferenceKeys.APPLICATION_OVERRIDE_LANGUAGE, null);
}
/** /**
* Set the value of application language shared preference. If set to null * Set the value of application language shared preference. If set to null
* the system language will be used. * the system language will be used.
......
// Copyright 2020 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.chrome.browser.language;
import android.content.Context;
import android.content.res.Configuration;
import android.text.TextUtils;
import org.chromium.base.LocaleUtils;
import java.util.Locale;
/**
* The global application language controller that uses the locale from
* {@link AppLocaleUtils#getAppLanguagePref} to override the locales in
* {@link ChromeApplication} and {@link ChromeActivity} and default Locale.
*/
public class GlobalAppLocaleController {
private static final GlobalAppLocaleController INSTANCE = new GlobalAppLocaleController();
// Set the original system language before Locale.getDefault() is overridden.
private final Locale mOriginalSystemLocal = Locale.getDefault();
private String mOverrideLanguage;
private boolean mIsOverridden;
private GlobalAppLocaleController() {}
/**
* Sets the global override language and override state based on the {@link AppLocaleUitls}
* shared preference. Should be called very early in {@link ChromeActivity#attachBaseContext}.
* @param context The Context to use to get the shared preference from.
* @return boolean Whether or not an override language is set.
*/
public boolean init(Context base) {
mOverrideLanguage = AppLocaleUtils.getAppLanguagePrefStartUp(base);
mIsOverridden = !TextUtils.isEmpty(mOverrideLanguage)
&& !TextUtils.equals(mOriginalSystemLocal.toLanguageTag(), mOverrideLanguage);
return mIsOverridden;
}
/**
* If the application should be overridden returns the override Configuration and updates the
* default LocaleList/Locale. Called early in {@link ChromeActivity#attachBaseContext}.
* @param base The base Context for the application and has the system locales.
* @return Configuration to override application context with or null.
*/
public Configuration getOverrideConfig(Context base) {
assert mIsOverridden : "Can only call GlobalAppLocaleController.getConfig if overridden";
Configuration config = new Configuration();
// Pre-Android O, fontScale gets initialized to 1 in the constructor. Set it to 0 so
// that applyOverrideConfiguration() does not interpret it as an overridden value.
// https://crbug.com/834191
config.fontScale = 0;
LocaleUtils.updateConfig(base, config, mOverrideLanguage);
LocaleUtils.setDefaultLocalesFromConfiguration(config);
return config;
}
/**
* Do the Activity level locale override if app locale preference is set.
* Should be called from {@link Activity#attachBaseContext()}.
* @param base The base Context for the Activity which has the system locales.
* @param config The Configuration that will be used to update the Activity.
* @return boolean Whether or not config was modified.
*/
public boolean applyActivityOverrides(Context base, Configuration config) {
if (!mIsOverridden) {
return false;
}
LocaleUtils.updateConfig(base, config, mOverrideLanguage);
return true;
}
/**
* Get the original application locale. If there is no override language this is
* the current application language.
* @return Locale of the original system language.
*/
public Locale getOriginalSystemLocale() {
return mOriginalSystemLocal;
}
/**
* Return the override state of the controller
* @return boolean Whether the Application locale is overridden.
*/
public boolean isOverridden() {
return mIsOverridden;
}
/**
* Return the GlobalAppLocaleController singleton instance.
* @return GlobalAppLocaleController singleton.
*/
public static GlobalAppLocaleController getInstance() {
return INSTANCE;
}
}
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