Merge "Fixing system language is not in all languages" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-10-21 11:02:16 +00:00
committed by Android (Google) Code Review
4 changed files with 256 additions and 120 deletions

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.app;
import static com.android.internal.app.AppLocaleStore.AppLocaleResult.LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_ASSET;
import static com.android.internal.app.AppLocaleStore.AppLocaleResult.LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG;
import android.content.Context;
import android.os.Build;
import android.os.LocaleList;
import android.util.Log;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
/** The Locale data collector for per-app language. */
class AppLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase {
private static final String TAG = AppLocaleCollector.class.getSimpleName();
private final Context mContext;
private final String mAppPackageName;
private final LocaleStore.LocaleInfo mAppCurrentLocale;
AppLocaleCollector(Context context, String appPackageName) {
mContext = context;
mAppPackageName = appPackageName;
mAppCurrentLocale = LocaleStore.getAppCurrentLocaleInfo(
mContext, mAppPackageName);
}
@Override
public HashSet<String> getIgnoredLocaleList(boolean translatedOnly) {
HashSet<String> langTagsToIgnore = new HashSet<>();
LocaleList systemLangList = LocaleList.getDefault();
for(int i = 0; i < systemLangList.size(); i++) {
langTagsToIgnore.add(systemLangList.get(i).toLanguageTag());
}
if (mAppCurrentLocale != null) {
langTagsToIgnore.add(mAppCurrentLocale.getLocale().toLanguageTag());
}
return langTagsToIgnore;
}
@Override
public Set<LocaleStore.LocaleInfo> getSupportedLocaleList(LocaleStore.LocaleInfo parent,
boolean translatedOnly, boolean isForCountryMode) {
AppLocaleStore.AppLocaleResult result =
AppLocaleStore.getAppSupportedLocales(mContext, mAppPackageName);
Set<String> langTagsToIgnore = getIgnoredLocaleList(translatedOnly);
Set<LocaleStore.LocaleInfo> appLocaleList = new HashSet<>();
Set<LocaleStore.LocaleInfo> systemLocaleList;
boolean shouldShowList =
result.mLocaleStatus == GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG
|| result.mLocaleStatus == GET_SUPPORTED_LANGUAGE_FROM_ASSET;
// Get system supported locale list
if (isForCountryMode) {
systemLocaleList = LocaleStore.getLevelLocales(mContext,
langTagsToIgnore, parent, translatedOnly);
} else {
systemLocaleList = LocaleStore.getLevelLocales(mContext, langTagsToIgnore,
null /* no parent */, translatedOnly);
}
// Add current app locale
if (mAppCurrentLocale != null && !isForCountryMode) {
appLocaleList.add(mAppCurrentLocale);
}
// Add current system language into suggestion list
for(LocaleStore.LocaleInfo localeInfo:
LocaleStore.getSystemCurrentLocaleInfo()) {
boolean isNotCurrentLocale = mAppCurrentLocale == null
|| !localeInfo.getLocale().equals(mAppCurrentLocale.getLocale());
if (!isForCountryMode && isNotCurrentLocale) {
appLocaleList.add(localeInfo);
}
}
// Add the languages that included in system supported locale
if (shouldShowList) {
appLocaleList.addAll(filterTheLanguagesNotIncludedInSystemLocale(
systemLocaleList, result.mAppSupportedLocales));
}
// Add "system language" option
if (!isForCountryMode && shouldShowList) {
appLocaleList.add(LocaleStore.getSystemDefaultLocaleInfo(
mAppCurrentLocale == null));
}
if (Build.isDebuggable()) {
Log.d(TAG, "App locale list: " + appLocaleList);
}
return appLocaleList;
}
@Override
public boolean hasSpecificPackageName() {
return true;
}
private Set<LocaleStore.LocaleInfo> filterTheLanguagesNotIncludedInSystemLocale(
Set<LocaleStore.LocaleInfo> systemLocaleList,
HashSet<Locale> appSupportedLocales) {
Set<LocaleStore.LocaleInfo> filteredList = new HashSet<>();
for(LocaleStore.LocaleInfo li: systemLocaleList) {
if (appSupportedLocales.contains(li.getLocale())) {
filteredList.add(li);
} else {
for(Locale l: appSupportedLocales) {
if(LocaleList.matchesLanguageAndScript(li.getLocale(), l)) {
filteredList.add(li);
break;
}
}
}
}
return filteredList;
}
}

View File

@@ -16,16 +16,12 @@
package com.android.internal.app;
import static com.android.internal.app.AppLocaleStore.AppLocaleResult.LocaleStatus;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.ListFragment;
import android.content.Context;
import android.os.Bundle;
import android.os.LocaleList;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -36,7 +32,6 @@ import android.widget.SearchView;
import com.android.internal.R;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
@@ -54,6 +49,7 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
private SuggestedLocaleAdapter mAdapter;
private LocaleSelectedListener mListener;
private LocaleCollectorBase mLocalePickerCollector;
private Set<LocaleStore.LocaleInfo> mLocaleList;
private LocaleStore.LocaleInfo mParentLocale;
private boolean mTranslatedOnly = false;
@@ -62,7 +58,6 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
private boolean mPreviousSearchHadFocus = false;
private int mFirstVisiblePosition = 0;
private int mTopDistance = 0;
private String mAppPackageName;
private CharSequence mTitle = null;
private OnActionExpandListener mOnActionExpandListener;
@@ -79,31 +74,50 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
void onLocaleSelected(LocaleStore.LocaleInfo locale);
}
private static LocalePickerWithRegion createCountryPicker(Context context,
/**
* The interface which provides the locale list.
*/
interface LocaleCollectorBase {
/** Gets the ignored locale list. */
HashSet<String> getIgnoredLocaleList(boolean translatedOnly);
/** Gets the supported locale list. */
Set<LocaleStore.LocaleInfo> getSupportedLocaleList(LocaleStore.LocaleInfo parent,
boolean translatedOnly, boolean isForCountryMode);
/** Indicates if the class work for specific package. */
boolean hasSpecificPackageName();
}
private static LocalePickerWithRegion createCountryPicker(
LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
boolean translatedOnly, String appPackageName,
OnActionExpandListener onActionExpandListener) {
boolean translatedOnly, OnActionExpandListener onActionExpandListener,
LocaleCollectorBase localePickerCollector) {
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
localePicker.setOnActionExpandListener(onActionExpandListener);
boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
translatedOnly, appPackageName);
boolean shouldShowTheList = localePicker.setListener(listener, parent,
translatedOnly, localePickerCollector);
return shouldShowTheList ? localePicker : null;
}
public static LocalePickerWithRegion createLanguagePicker(Context context,
LocaleSelectedListener listener, boolean translatedOnly) {
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
localePicker.setListener(context, listener, /* parent */ null, translatedOnly, null);
return localePicker;
return createLanguagePicker(context, listener, translatedOnly, null, null);
}
public static LocalePickerWithRegion createLanguagePicker(Context context,
LocaleSelectedListener listener, boolean translatedOnly, String appPackageName,
OnActionExpandListener onActionExpandListener) {
LocaleCollectorBase localePickerController;
if (TextUtils.isEmpty(appPackageName)) {
localePickerController = new SystemLocaleCollector(context);
} else {
localePickerController = new AppLocaleCollector(context, appPackageName);
}
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
localePicker.setOnActionExpandListener(onActionExpandListener);
localePicker.setListener(
context, listener, /* parent */ null, translatedOnly, appPackageName);
localePicker.setListener(listener, /* parent */ null, translatedOnly,
localePickerController);
return localePicker;
}
@@ -120,109 +134,23 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
* In this case we don't even show the list, we call the listener with that locale,
* "pretending" it was selected, and return false.</p>
*/
private boolean setListener(Context context, LocaleSelectedListener listener,
LocaleStore.LocaleInfo parent, boolean translatedOnly, String appPackageName) {
private boolean setListener(LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
boolean translatedOnly, LocaleCollectorBase localePickerController) {
this.mParentLocale = parent;
this.mListener = listener;
this.mTranslatedOnly = translatedOnly;
this.mAppPackageName = appPackageName;
this.mLocalePickerCollector = localePickerController;
setRetainInstance(true);
final HashSet<String> langTagsToIgnore = new HashSet<>();
LocaleStore.LocaleInfo appCurrentLocale =
LocaleStore.getAppCurrentLocaleInfo(context, appPackageName);
boolean isForCountryMode = parent != null;
mLocaleList = localePickerController.getSupportedLocaleList(
parent, translatedOnly, parent != null);
if (!TextUtils.isEmpty(appPackageName) && !isForCountryMode) {
// Filter current system locale to add them into suggestion
LocaleList systemLangList = LocaleList.getDefault();
for(int i = 0; i < systemLangList.size(); i++) {
langTagsToIgnore.add(systemLangList.get(i).toLanguageTag());
}
if (appCurrentLocale != null) {
Log.d(TAG, "appCurrentLocale: " + appCurrentLocale.getLocale().toLanguageTag());
langTagsToIgnore.add(appCurrentLocale.getLocale().toLanguageTag());
} else {
Log.d(TAG, "appCurrentLocale is null");
}
} else if (!translatedOnly) {
final LocaleList userLocales = LocalePicker.getLocales();
final String[] langTags = userLocales.toLanguageTags().split(",");
Collections.addAll(langTagsToIgnore, langTags);
}
if (isForCountryMode) {
mLocaleList = LocaleStore.getLevelLocales(context,
langTagsToIgnore, parent, translatedOnly);
if (mLocaleList.size() <= 1) {
if (listener != null && (mLocaleList.size() == 1)) {
listener.onLocaleSelected(mLocaleList.iterator().next());
}
return false;
}
if (parent != null && listener != null && mLocaleList.size() == 1) {
listener.onLocaleSelected(mLocaleList.iterator().next());
return false;
} else {
mLocaleList = LocaleStore.getLevelLocales(context, langTagsToIgnore,
null /* no parent */, translatedOnly);
return true;
}
Log.d(TAG, "mLocaleList size: " + mLocaleList.size());
// Adding current locale and system default option into suggestion list
if(!TextUtils.isEmpty(appPackageName)) {
if (appCurrentLocale != null && !isForCountryMode) {
mLocaleList.add(appCurrentLocale);
}
AppLocaleStore.AppLocaleResult result =
AppLocaleStore.getAppSupportedLocales(context, appPackageName);
boolean shouldShowList =
result.mLocaleStatus == LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG
|| result.mLocaleStatus == LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_ASSET;
// Add current system language into suggestion list
for(LocaleStore.LocaleInfo localeInfo: LocaleStore.getSystemCurrentLocaleInfo()) {
boolean isNotCurrentLocale = appCurrentLocale == null
|| !localeInfo.getLocale().equals(appCurrentLocale.getLocale());
if (!isForCountryMode && isNotCurrentLocale) {
mLocaleList.add(localeInfo);
}
}
// Filter the language not support in app
mLocaleList = filterTheLanguagesNotSupportedInApp(
shouldShowList, result.mAppSupportedLocales);
Log.d(TAG, "mLocaleList after app-supported filter: " + mLocaleList.size());
// Add "system language"
if (!isForCountryMode && shouldShowList) {
mLocaleList.add(LocaleStore.getSystemDefaultLocaleInfo(appCurrentLocale == null));
}
}
return true;
}
private Set<LocaleStore.LocaleInfo> filterTheLanguagesNotSupportedInApp(
boolean shouldShowList, HashSet<Locale> supportedLocales) {
Set<LocaleStore.LocaleInfo> filteredList = new HashSet<>();
if (!shouldShowList) {
return filteredList;
}
for(LocaleStore.LocaleInfo li: mLocaleList) {
if (supportedLocales.contains(li.getLocale())) {
filteredList.add(li);
} else {
for(Locale l: supportedLocales) {
if(LocaleList.matchesLanguageAndScript(li.getLocale(), l)) {
filteredList.add(li);
break;
}
}
}
}
return filteredList;
}
private void returnToParentFrame() {
@@ -246,7 +174,9 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
mTitle = getActivity().getTitle();
final boolean countryMode = mParentLocale != null;
final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode, mAppPackageName);
final boolean hasSpecificPackageName =
mLocalePickerCollector != null && mLocalePickerCollector.hasSpecificPackageName();
mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode, hasSpecificPackageName);
final LocaleHelper.LocaleInfoComparator comp =
new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
mAdapter.sort(comp);
@@ -321,8 +251,8 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
returnToParentFrame();
} else {
LocalePickerWithRegion selector = LocalePickerWithRegion.createCountryPicker(
getContext(), mListener, locale, mTranslatedOnly /* translate only */,
mAppPackageName, mOnActionExpandListener);
mListener, locale, mTranslatedOnly /* translate only */,
mOnActionExpandListener, this.mLocalePickerCollector);
if (selector != null) {
getFragmentManager().beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
@@ -340,7 +270,8 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
inflater.inflate(R.menu.language_selection_list, menu);
final MenuItem searchMenuItem = menu.findItem(R.id.locale_search_menu);
if (!TextUtils.isEmpty(mAppPackageName) && mOnActionExpandListener != null) {
if (mLocalePickerCollector.hasSpecificPackageName()
&& mOnActionExpandListener != null) {
searchMenuItem.setOnActionExpandListener(mOnActionExpandListener);
}

View File

@@ -70,17 +70,17 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
private Locale mDisplayLocale = null;
// used to potentially cache a modified Context that uses mDisplayLocale
private Context mContextOverride = null;
private String mAppPackageName;
private boolean mHasSpecificAppPackageName;
public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode) {
this(localeOptions, countryMode, null);
this(localeOptions, countryMode, false);
}
public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode,
String appPackageName) {
boolean hasSpecificAppPackageName) {
mCountryMode = countryMode;
mLocaleOptions = new ArrayList<>(localeOptions.size());
mAppPackageName = appPackageName;
mHasSpecificAppPackageName = hasSpecificAppPackageName;
for (LocaleStore.LocaleInfo li : localeOptions) {
if (li.isSuggested()) {
@@ -134,7 +134,7 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
@Override
public int getViewTypeCount() {
if (!TextUtils.isEmpty(mAppPackageName) && showHeaders()) {
if (mHasSpecificAppPackageName && showHeaders()) {
// Two headers, 1 "System language", 1 current locale
return APP_LANGUAGE_PICKER_TYPE_COUNT;
} else if (showHeaders()) {

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.app;
import android.content.Context;
import android.os.LocaleList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/** The Locale data collector for System language. */
class SystemLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase {
private final Context mContext;
SystemLocaleCollector(Context context) {
mContext = context;
}
@Override
public HashSet<String> getIgnoredLocaleList(boolean translatedOnly) {
HashSet<String> ignoreList = new HashSet<>();
if (!translatedOnly) {
final LocaleList userLocales = LocalePicker.getLocales();
final String[] langTags = userLocales.toLanguageTags().split(",");
Collections.addAll(ignoreList, langTags);
}
return ignoreList;
}
@Override
public Set<LocaleStore.LocaleInfo> getSupportedLocaleList(LocaleStore.LocaleInfo parent,
boolean translatedOnly, boolean isForCountryMode) {
Set<String> langTagsToIgnore = getIgnoredLocaleList(translatedOnly);
Set<LocaleStore.LocaleInfo> localeList;
if (isForCountryMode) {
localeList = LocaleStore.getLevelLocales(mContext,
langTagsToIgnore, parent, translatedOnly);
} else {
localeList = LocaleStore.getLevelLocales(mContext, langTagsToIgnore,
null /* no parent */, translatedOnly);
}
return localeList;
}
@Override
public boolean hasSpecificPackageName() {
return false;
}
}