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

Commit 80d38949 authored by Calvin Pan's avatar Calvin Pan Committed by Android (Google) Code Review
Browse files

Merge "Fixing system language is not in all languages"

parents a30220b8 fe7b9a7e
Loading
Loading
Loading
Loading
+139 −0
Original line number Original line 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 Original line Diff line number Diff line
@@ -16,16 +16,12 @@


package com.android.internal.app;
package com.android.internal.app;


import static com.android.internal.app.AppLocaleStore.AppLocaleResult.LocaleStatus;

import android.app.FragmentManager;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.FragmentTransaction;
import android.app.ListFragment;
import android.app.ListFragment;
import android.content.Context;
import android.content.Context;
import android.os.Bundle;
import android.os.Bundle;
import android.os.LocaleList;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MenuItem;
@@ -36,7 +32,6 @@ import android.widget.SearchView;


import com.android.internal.R;
import com.android.internal.R;


import java.util.Collections;
import java.util.HashSet;
import java.util.HashSet;
import java.util.Locale;
import java.util.Locale;
import java.util.Set;
import java.util.Set;
@@ -54,6 +49,7 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O


    private SuggestedLocaleAdapter mAdapter;
    private SuggestedLocaleAdapter mAdapter;
    private LocaleSelectedListener mListener;
    private LocaleSelectedListener mListener;
    private LocaleCollectorBase mLocalePickerCollector;
    private Set<LocaleStore.LocaleInfo> mLocaleList;
    private Set<LocaleStore.LocaleInfo> mLocaleList;
    private LocaleStore.LocaleInfo mParentLocale;
    private LocaleStore.LocaleInfo mParentLocale;
    private boolean mTranslatedOnly = false;
    private boolean mTranslatedOnly = false;
@@ -62,7 +58,6 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
    private boolean mPreviousSearchHadFocus = false;
    private boolean mPreviousSearchHadFocus = false;
    private int mFirstVisiblePosition = 0;
    private int mFirstVisiblePosition = 0;
    private int mTopDistance = 0;
    private int mTopDistance = 0;
    private String mAppPackageName;
    private CharSequence mTitle = null;
    private CharSequence mTitle = null;
    private OnActionExpandListener mOnActionExpandListener;
    private OnActionExpandListener mOnActionExpandListener;


@@ -79,31 +74,50 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
        void onLocaleSelected(LocaleStore.LocaleInfo locale);
        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,
            LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
            boolean translatedOnly, String appPackageName,
            boolean translatedOnly, OnActionExpandListener onActionExpandListener,
            OnActionExpandListener onActionExpandListener) {
            LocaleCollectorBase localePickerCollector) {
        LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
        LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
        localePicker.setOnActionExpandListener(onActionExpandListener);
        localePicker.setOnActionExpandListener(onActionExpandListener);
        boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
        boolean shouldShowTheList = localePicker.setListener(listener, parent,
                translatedOnly, appPackageName);
                translatedOnly, localePickerCollector);
        return shouldShowTheList ? localePicker : null;
        return shouldShowTheList ? localePicker : null;
    }
    }


    public static LocalePickerWithRegion createLanguagePicker(Context context,
    public static LocalePickerWithRegion createLanguagePicker(Context context,
            LocaleSelectedListener listener, boolean translatedOnly) {
            LocaleSelectedListener listener, boolean translatedOnly) {
        LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
        return createLanguagePicker(context, listener, translatedOnly, null, null);
        localePicker.setListener(context, listener, /* parent */ null, translatedOnly, null);
        return localePicker;
    }
    }


    public static LocalePickerWithRegion createLanguagePicker(Context context,
    public static LocalePickerWithRegion createLanguagePicker(Context context,
            LocaleSelectedListener listener, boolean translatedOnly, String appPackageName,
            LocaleSelectedListener listener, boolean translatedOnly, String appPackageName,
            OnActionExpandListener onActionExpandListener) {
            OnActionExpandListener onActionExpandListener) {
        LocaleCollectorBase localePickerController;
        if (TextUtils.isEmpty(appPackageName)) {
            localePickerController = new SystemLocaleCollector(context);
        } else {
            localePickerController = new AppLocaleCollector(context, appPackageName);
        }
        LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
        LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
        localePicker.setOnActionExpandListener(onActionExpandListener);
        localePicker.setOnActionExpandListener(onActionExpandListener);
        localePicker.setListener(
        localePicker.setListener(listener, /* parent */ null, translatedOnly,
                context, listener, /* parent */ null, translatedOnly, appPackageName);
                localePickerController);
        return localePicker;
        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,
     * 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>
     * "pretending" it was selected, and return false.</p>
     */
     */
    private boolean setListener(Context context, LocaleSelectedListener listener,
    private boolean setListener(LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
            LocaleStore.LocaleInfo parent, boolean translatedOnly, String appPackageName) {
            boolean translatedOnly, LocaleCollectorBase localePickerController) {
        this.mParentLocale = parent;
        this.mParentLocale = parent;
        this.mListener = listener;
        this.mListener = listener;
        this.mTranslatedOnly = translatedOnly;
        this.mTranslatedOnly = translatedOnly;
        this.mAppPackageName = appPackageName;
        this.mLocalePickerCollector = localePickerController;
        setRetainInstance(true);
        setRetainInstance(true);


        final HashSet<String> langTagsToIgnore = new HashSet<>();
        mLocaleList = localePickerController.getSupportedLocaleList(
        LocaleStore.LocaleInfo appCurrentLocale =
                parent, translatedOnly, parent != null);
                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);
        }


        if (isForCountryMode) {
        if (parent != null && listener != null && mLocaleList.size() == 1) {
            mLocaleList = LocaleStore.getLevelLocales(context,
                    langTagsToIgnore, parent, translatedOnly);
            if (mLocaleList.size() <= 1) {
                if (listener != null && (mLocaleList.size() == 1)) {
            listener.onLocaleSelected(mLocaleList.iterator().next());
            listener.onLocaleSelected(mLocaleList.iterator().next());
                }
            return false;
            return false;
            }
        } else {
        } 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;
            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() {
    private void returnToParentFrame() {
@@ -246,7 +174,9 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
        mTitle = getActivity().getTitle();
        mTitle = getActivity().getTitle();
        final boolean countryMode = mParentLocale != null;
        final boolean countryMode = mParentLocale != null;
        final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
        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 =
        final LocaleHelper.LocaleInfoComparator comp =
                new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
                new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
        mAdapter.sort(comp);
        mAdapter.sort(comp);
@@ -321,8 +251,8 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
            returnToParentFrame();
            returnToParentFrame();
        } else {
        } else {
            LocalePickerWithRegion selector = LocalePickerWithRegion.createCountryPicker(
            LocalePickerWithRegion selector = LocalePickerWithRegion.createCountryPicker(
                    getContext(), mListener, locale, mTranslatedOnly /* translate only */,
                    mListener, locale, mTranslatedOnly /* translate only */,
                    mAppPackageName, mOnActionExpandListener);
                    mOnActionExpandListener, this.mLocalePickerCollector);
            if (selector != null) {
            if (selector != null) {
                getFragmentManager().beginTransaction()
                getFragmentManager().beginTransaction()
                        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                        .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);
            inflater.inflate(R.menu.language_selection_list, menu);


            final MenuItem searchMenuItem = menu.findItem(R.id.locale_search_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);
                searchMenuItem.setOnActionExpandListener(mOnActionExpandListener);
            }
            }


+5 −5
Original line number Original line Diff line number Diff line
@@ -69,17 +69,17 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
    protected Locale mDisplayLocale = null;
    protected Locale mDisplayLocale = null;
    // used to potentially cache a modified Context that uses mDisplayLocale
    // used to potentially cache a modified Context that uses mDisplayLocale
    protected Context mContextOverride = null;
    protected Context mContextOverride = null;
    private String mAppPackageName;
    private boolean mHasSpecificAppPackageName;


    public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode) {
    public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode) {
        this(localeOptions, countryMode, null);
        this(localeOptions, countryMode, false);
    }
    }


    public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode,
    public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode,
            String appPackageName) {
            boolean hasSpecificAppPackageName) {
        mCountryMode = countryMode;
        mCountryMode = countryMode;
        mLocaleOptions = new ArrayList<>(localeOptions.size());
        mLocaleOptions = new ArrayList<>(localeOptions.size());
        mAppPackageName = appPackageName;
        mHasSpecificAppPackageName = hasSpecificAppPackageName;


        for (LocaleStore.LocaleInfo li : localeOptions) {
        for (LocaleStore.LocaleInfo li : localeOptions) {
            if (li.isSuggested()) {
            if (li.isSuggested()) {
@@ -136,7 +136,7 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {


    @Override
    @Override
    public int getViewTypeCount() {
    public int getViewTypeCount() {
        if (!TextUtils.isEmpty(mAppPackageName) && showHeaders()) {
        if (mHasSpecificAppPackageName && showHeaders()) {
            // Two headers, 1 "System language", 1 current locale
            // Two headers, 1 "System language", 1 current locale
            return APP_LANGUAGE_PICKER_TYPE_COUNT;
            return APP_LANGUAGE_PICKER_TYPE_COUNT;
        } else if (showHeaders()) {
        } else if (showHeaders()) {
+66 −0
Original line number Original line 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