diff options
4 files changed, 256 insertions, 120 deletions
diff --git a/core/java/com/android/internal/app/AppLocaleCollector.java b/core/java/com/android/internal/app/AppLocaleCollector.java new file mode 100644 index 000000000000..65e8c646e17d --- /dev/null +++ b/core/java/com/android/internal/app/AppLocaleCollector.java @@ -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; + } +} diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java index 965895f08d6e..3efd279c2639 100644 --- a/core/java/com/android/internal/app/LocalePickerWithRegion.java +++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java @@ -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; - - 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); - } + mLocaleList = localePickerController.getSupportedLocaleList( + parent, translatedOnly, parent != null); - 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); } diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java index 1be1247b7cc0..5ed0e8bc7883 100644 --- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java +++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java @@ -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()) { diff --git a/core/java/com/android/internal/app/SystemLocaleCollector.java b/core/java/com/android/internal/app/SystemLocaleCollector.java new file mode 100644 index 000000000000..9a6d4c192fdc --- /dev/null +++ b/core/java/com/android/internal/app/SystemLocaleCollector.java @@ -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; + } +}
\ No newline at end of file |