Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 686f5b9c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents fc3a434b c41d594e
Loading
Loading
Loading
Loading
+139 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}
+46 −115
Original line number Diff line number Diff line
@@ -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)) {
        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);
        }
        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);
            }

+5 −5
Original line number Diff line number Diff line
@@ -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()) {
+66 −0
Original line number Diff line number Diff line
/*
 * 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