Commit c1f0e65c authored by Trevor Perrier's avatar Trevor Perrier Committed by Chromium LUCI CQ

[Android] Add app and target language to detailed language settings.

This CL enables selecting the app and translate target languages in
the new detailed language settings on Android.  This feature is all
behind a release flag.

Both settings preferences use the added LanguageItemPreference which
launches the existing AddLanguageFragment on tap to select a language.
Languages options in the AddLanguageFragment are filtered based on what
the language will be used for.

setTargetLanguage is added to the TranslateBridge.

The Advanced Settings section is implemented as an Expandable
Preference Group.  Currently the only preference that works in the
advanced section is the Target Language.

Screenshots can be found here: https://crbug.com/1127531#c5

Bug: 1127531
Change-Id: I18707df2e3736920d1e7a4102b55863b99eb21e3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2593923
Commit-Queue: Trevor  Perrier <perrier@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarNatalie Chouinard <chouinard@chromium.org>
Reviewed-by: default avatarMegan Jablonski <megjablon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842665}
parent f9b806e5
......@@ -752,8 +752,8 @@ chrome_java_sources = [
"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/AvailableUiLanguages.java",
"java/src/org/chromium/chrome/browser/language/settings/DetailedLanguageListPreference.java",
"java/src/org/chromium/chrome/browser/language/settings/LanguageItem.java",
"java/src/org/chromium/chrome/browser/language/settings/LanguageItemPickerPreference.java",
"java/src/org/chromium/chrome/browser/language/settings/LanguageListBaseAdapter.java",
"java/src/org/chromium/chrome/browser/language/settings/LanguageListPreference.java",
"java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java",
......
......@@ -4,16 +4,47 @@
found in the LICENSE file. -->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<org.chromium.chrome.browser.language.settings.DetailedLanguageListPreference
android:key="preferred_languages"
android:layout="@layout/languages_preference"
android:widgetLayout="@layout/accept_languages_list" />
<PreferenceCategory
android:key="app_language_section"
android:order="1">
<org.chromium.components.browser_ui.settings.ChromeSwitchPreference
android:key="translate_switch"
android:summaryOn="@string/languages_offer_translate_switch"
android:summaryOff="@string/languages_offer_translate_switch" />
<org.chromium.chrome.browser.language.settings.LanguageItemPickerPreference
android:key="app_language_preference" />
</PreferenceCategory>
<PreferenceCategory
android:key="content_langauges_section"
android:title="@string/languages_content_title"
android:order="2"
app:allowDividerAbove="true">
<org.chromium.chrome.browser.language.settings.LanguageListPreference
android:key="content_languages_preference"
android:layout="@layout/languages_preference"
android:widgetLayout="@layout/accept_languages_list" />
</PreferenceCategory>
<PreferenceCategory
android:key="translation_settings_section"
android:order="3"
android:title="@string/languages_settings_title"
app:initialExpandedChildrenCount="1">
<org.chromium.components.browser_ui.settings.ChromeSwitchPreference
android:key="translate_switch"
android:summaryOn="@string/languages_send_translate_switch"
android:summaryOff="@string/languages_send_translate_switch" />
<org.chromium.chrome.browser.language.settings.LanguageItemPickerPreference
android:key="translate_settings_target_language"
android:title="@string/languages_settings_target"
app:allowDividerBelow="false" />
</PreferenceCategory>
</PreferenceScreen>
......@@ -30,6 +30,9 @@ public class AppLocaleUtils {
private static final String TAG = "AppLocale";
// Value of AppLocale preference when the system language is used.
public static final String SYSTEM_LANGUAGE_VALUE = null;
/**
* Return true if languageName is the same as the current application override
* language stored preference.
......@@ -45,7 +48,7 @@ public class AppLocaleUtils {
*/
public static String getAppLanguagePref() {
return SharedPreferencesManager.getInstance().readString(
ChromePreferenceKeys.APPLICATION_OVERRIDE_LANGUAGE, null);
ChromePreferenceKeys.APPLICATION_OVERRIDE_LANGUAGE, SYSTEM_LANGUAGE_VALUE);
}
/**
......@@ -58,7 +61,7 @@ public class AppLocaleUtils {
@SuppressWarnings("DefaultSharedPreferencesCheck")
protected static String getAppLanguagePrefStartUp(Context base) {
return PreferenceManager.getDefaultSharedPreferences(base).getString(
ChromePreferenceKeys.APPLICATION_OVERRIDE_LANGUAGE, null);
ChromePreferenceKeys.APPLICATION_OVERRIDE_LANGUAGE, SYSTEM_LANGUAGE_VALUE);
}
/**
......@@ -69,7 +72,7 @@ public class AppLocaleUtils {
SharedPreferencesManager.getInstance().writeString(
ChromePreferenceKeys.APPLICATION_OVERRIDE_LANGUAGE, languageName);
if (BundleUtils.isBundle()) {
ensureLaguageSplitInstalled(languageName);
ensureLanguageSplitInstalled(languageName);
}
}
......@@ -89,14 +92,14 @@ public class AppLocaleUtils {
}
/**
* For bundle builds ensure that the language split for languageName is download.
* For bundle builds ensure that the language split for languageName is downloaded.
*/
private static void ensureLaguageSplitInstalled(String languageName) {
private static void ensureLanguageSplitInstalled(String languageName) {
SplitInstallManager splitInstallManager =
SplitInstallManagerFactory.create(ContextUtils.getApplicationContext());
// TODO(perrier): check if languageName is already installed. https://crbug.com/1103806
if (languageName != null) {
if (!TextUtils.equals(languageName, SYSTEM_LANGUAGE_VALUE)) {
SplitInstallRequest installRequest =
SplitInstallRequest.newBuilder()
.addLanguage(Locale.forLanguageTag(languageName))
......
......@@ -24,6 +24,7 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.components.browser_ui.settings.SettingsUtils;
import java.util.ArrayList;
......@@ -35,7 +36,14 @@ import java.util.Locale;
* accept languages. There is a {@link SearchView} on its Actionbar to make a quick lookup.
*/
public class AddLanguageFragment extends Fragment {
static final String INTENT_NEW_ACCEPT_LANGUAGE = "AddLanguageFragment.NewLanguage";
// Intent key to pass selected language code from AddLanguageFragment.
static final String INTENT_SELECTED_LANGUAGE = "AddLanguageFragment.SelectedLanguages";
// Intent key to receive type of languages to populate fragment with.
static final String INTENT_LANGUAGE_OPTIONS = "AddLanguageFragment.LanguageOptions";
// Intent keys to select language options to use.
static final int LANGUAGE_OPTIONS_ACCEPT_LANGUAGES = 0; // Default
static final int LANGUAGE_OPTIONS_UI_LANGUAGES = 1;
static final int LANGUAGE_OPTIONS_TRANSLATE_LANGUAGES = 2;
/**
* A host to launch AddLanguageFragment and receive the result.
......@@ -97,7 +105,11 @@ public class AddLanguageFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTitle(R.string.add_language);
if (ChromeFeatureList.isEnabled(ChromeFeatureList.DETAILED_LANGUAGE_SETTINGS)) {
getActivity().setTitle(R.string.languages_select);
} else {
getActivity().setTitle(R.string.add_language);
}
setHasOptionsMenu(true);
LanguagesManager.recordImpression(
LanguagesManager.LanguageSettingsPageType.PAGE_ADD_LANGUAGE);
......@@ -117,10 +129,20 @@ public class AddLanguageFragment extends Fragment {
mRecyclerView.addItemDecoration(
new DividerItemDecoration(activity, layoutManager.getOrientation()));
mFullLanguageList = LanguagesManager.getInstance().getLanguageItemsExcludingUserAccept();
int languageOption = getActivity().getIntent().getIntExtra(
INTENT_LANGUAGE_OPTIONS, LANGUAGE_OPTIONS_ACCEPT_LANGUAGES);
if (languageOption == LANGUAGE_OPTIONS_UI_LANGUAGES) {
mFullLanguageList = LanguagesManager.getInstance().getAvailableUiLanguageItems();
mFullLanguageList.add(0, LanguageItem.makeSystemDefaultLanguageItem());
} else if (languageOption == LANGUAGE_OPTIONS_TRANSLATE_LANGUAGES) {
mFullLanguageList = LanguagesManager.getInstance().getTranslateLanguageItems();
} else {
mFullLanguageList =
LanguagesManager.getInstance().getLanguageItemsExcludingUserAccept();
}
mItemClickListener = item -> {
Intent intent = new Intent();
intent.putExtra(INTENT_NEW_ACCEPT_LANGUAGE, item.getCode());
intent.putExtra(INTENT_SELECTED_LANGUAGE, item.getCode());
activity.setResult(Activity.RESULT_OK, intent);
activity.finish();
};
......
......@@ -4,6 +4,15 @@
package org.chromium.chrome.browser.language.settings;
import android.text.TextUtils;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.language.AppLocaleUtils;
import org.chromium.chrome.browser.language.GlobalAppLocaleController;
import java.util.Locale;
/**
* Simple object representing the language item.
*/
......@@ -31,7 +40,11 @@ public class LanguageItem {
mDisplayName = displayName;
mNativeDisplayName = nativeDisplayName;
mSupportTranslate = supportTranslate;
mSupportAppUI = AvailableUiLanguages.isAvailable(mCode);
if (TextUtils.equals(code, AppLocaleUtils.SYSTEM_LANGUAGE_VALUE)) {
mSupportAppUI = true; // system language is a supported UI language
} else {
mSupportAppUI = AvailableUiLanguages.isAvailable(mCode);
}
}
/**
......@@ -68,4 +81,18 @@ public class LanguageItem {
public boolean isUISupported() {
return mSupportAppUI;
}
/**
* Create a LanguageItem representing the system default language.
* @return LanguageItem
*/
public static LanguageItem makeSystemDefaultLanguageItem() {
String displayName = ContextUtils.getApplicationContext().getResources().getString(
R.string.default_lang_subtitle);
String nativeName =
GlobalAppLocaleController.getInstance().getOriginalSystemLocale().getDisplayName(
Locale.getDefault());
return new LanguageItem(
AppLocaleUtils.SYSTEM_LANGUAGE_VALUE, displayName, nativeName, true);
}
}
// 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.settings;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import org.chromium.chrome.browser.language.AppLocaleUtils;
import org.chromium.components.browser_ui.settings.ChromeBasePreference;
/**
* Chrome Preference that enables selecting a single LanguageItem.
*/
public class LanguageItemPickerPreference extends ChromeBasePreference {
private LanguageItem mLanguageItem;
private boolean mUseLanguageItemForTitle;
public LanguageItemPickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Set the LanguageItem value.
* @param LanguageItem The LanguageItem to use for this preference
*/
public void setLanguageItem(LanguageItem languageItem) {
assert languageItem != null;
mLanguageItem = languageItem;
updateDisplay();
}
/**
* Set the LanguageItem value based on the string locale code. If null is used the system
* default language is set as the preference's LanguageItem
* @param String languageCode The iso639 languageCode for LanguageItem
*/
public void setLanguageItem(String languageCode) {
LanguageItem languageItem;
if (TextUtils.equals(languageCode, AppLocaleUtils.SYSTEM_LANGUAGE_VALUE)) {
languageItem = LanguageItem.makeSystemDefaultLanguageItem();
} else {
languageItem = LanguagesManager.getInstance().getLanguageItem(languageCode);
}
setLanguageItem(languageItem);
}
/**
* By default only the summary text is synced to the LanguageItem. Enabling this will make the
* preference title the display name and summary the native display name.
* @param boolean use
*/
public void useLanguageItemForTitle(boolean useForTitle) {
mUseLanguageItemForTitle = useForTitle;
updateDisplay();
}
/**
* Update the title and summary to display
*/
private void updateDisplay() {
if (mLanguageItem == null) {
return;
} else if (mUseLanguageItemForTitle) {
setTitle(mLanguageItem.getDisplayName());
setSummary(mLanguageItem.getNativeDisplayName());
} else {
setSummary(mLanguageItem.getDisplayName());
}
}
}
......@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.language.settings;
import androidx.annotation.IntDef;
import org.chromium.base.LocaleUtils;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.translate.TranslateBridge;
......@@ -123,6 +124,43 @@ public class LanguagesManager {
return results;
}
/**
* Get a list of LanguageItems that can be Chrome UI languages.
* @return List of LanguageItems.
*/
public List<LanguageItem> getAvailableUiLanguageItems() {
List<LanguageItem> results = new ArrayList<>();
for (LanguageItem item : mLanguagesMap.values()) {
if (item.isUISupported()) results.add(item);
}
return results;
}
/**
* Get a list of LanguageItems that are translatable.
* @return List of LanguageItems.
*/
public List<LanguageItem> getTranslateLanguageItems() {
List<LanguageItem> results = new ArrayList<>();
for (LanguageItem item : mLanguagesMap.values()) {
if (item.isSupported()) results.add(item);
}
return results;
}
/**
* Get a LanguageItem given the iso639 locale code (e.g. en-US). If no direct match is found
* only the language is checked. If there is still no match null is returned.
* @return LanguageItem or null if none found
*/
public LanguageItem getLanguageItem(String localeCode) {
LanguageItem result = mLanguagesMap.get(localeCode);
if (result != null) return result;
String baseLanguage = LocaleUtils.toLanguage(localeCode);
return mLanguagesMap.get(baseLanguage);
}
/**
* Add a language to the current user's accept languages.
* @param code The language code to remove.
......
......@@ -81,6 +81,14 @@ public class TranslateBridge {
return TranslateBridgeJni.get().getTargetLanguage();
}
/**
* Set the default target language the Translate Service will use.
* @param String targetLanguage Language code of new target language.
*/
public static void setDefaultTargetLanguage(String targetLanguage) {
TranslateBridgeJni.get().setDefaultTargetLanguage(targetLanguage);
}
/** @return whether the given string is blocked for translation. */
public static boolean isBlockedLanguage(String language) {
return TranslateBridgeJni.get().isBlockedLanguage(language);
......@@ -224,6 +232,7 @@ public class TranslateBridge {
String getOriginalLanguage(WebContents webContents);
String getCurrentLanguage(WebContents webContents);
String getTargetLanguage();
void setDefaultTargetLanguage(String targetLanguage);
boolean isBlockedLanguage(String language);
void getModelLanguages(LinkedHashSet<String> set);
void resetAcceptLanguages(String defaultLocale);
......
......@@ -184,6 +184,16 @@ JNI_TranslateBridge_GetTargetLanguage(JNIEnv* env) {
return j_target_language;
}
// Set the default target language to translate into for this user.
static void JNI_TranslateBridge_SetDefaultTargetLanguage(
JNIEnv* env,
const JavaParamRef<jstring>& j_target_language) {
std::unique_ptr<translate::TranslatePrefs> translate_prefs =
ChromeTranslateClient::CreateTranslatePrefs(GetPrefService());
std::string target_language(ConvertJavaStringToUTF8(env, j_target_language));
translate_prefs->SetRecentTargetLanguage(target_language);
}
// Determines whether the given language is blocked for translation.
static jboolean JNI_TranslateBridge_IsBlockedLanguage(
JNIEnv* env,
......
......@@ -1187,12 +1187,6 @@ Your Google account may have other forms of browsing history like searches and a
<message name="IDS_LANGUAGES_ITEM_OPTION_OFFER_TO_TRANSLATE" desc="Option in language item menu. User can click the 'Offer to translate' option to toggle whether they want Chrome to translate pages in this language. [CHAR-LIMIT=32]">
Offer to translate
</message>
<message name="IDS_LANGUAGES_SET_APPLICATION_LANGUAGE_PROMPT" desc="Option in language item menu. User can click the 'App Language' option to toggle whether or not the Chrome user interface should be displayed in this language. [CHAR-LIMIT=32]">
Use as Chrome’s language
</message>
<message name="IDS_LANGUAGES_SET_AS_APPLICATION_LANGUAGE" desc="Toast to display after selecting language to use for Chrome's user interface.">
<ph name="APP_NAME">%1$s<ex>Chrome</ex></ph> will use <ph name="language">%2$s<ex>Hindi</ex></ph> on restart.
</message>
<message name="IDS_LANGUAGES_EXPLICIT_ASK_TITLE" desc="Title of the dialog that explicitly asks the user which languages they can read.">
What languages do you read?
</message>
......
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