11808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita/*
21808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * Copyright (C) 2016 The Android Open Source Project
31808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita *
41808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * Licensed under the Apache License, Version 2.0 (the "License");
51808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * you may not use this file except in compliance with the License.
61808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * You may obtain a copy of the License at
71808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita *
81808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita *      http://www.apache.org/licenses/LICENSE-2.0
91808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita *
101808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * Unless required by applicable law or agreed to in writing, software
111808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * distributed under the License is distributed on an "AS IS" BASIS,
121808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * See the License for the specific language governing permissions and
141808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * limitations under the License.
151808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita */
161808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
171808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitapackage com.android.internal.app;
181808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
193f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournaderimport android.annotation.NonNull;
203f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournaderimport android.annotation.Nullable;
213f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournaderimport android.content.Context;
223f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournaderimport android.content.res.Configuration;
2324215ecadce5f44de33959b4f512482f39ac4c92Mihai Nitaimport android.text.TextUtils;
241808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport android.view.LayoutInflater;
251808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport android.view.View;
261808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport android.view.ViewGroup;
271808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport android.widget.BaseAdapter;
281808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport android.widget.Filter;
291808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport android.widget.Filterable;
301808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport android.widget.TextView;
311808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
321808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport com.android.internal.R;
331808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
341808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport java.util.ArrayList;
351808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport java.util.Collections;
361808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport java.util.Locale;
371808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nitaimport java.util.Set;
381808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
391808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
401808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita/**
411808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * This adapter wraps around a regular ListAdapter for LocaleInfo, and creates 2 sections.
421808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita *
431808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * <p>The first section contains "suggested" languages (usually including a region),
441808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * the second section contains all the languages within the original adapter.
451808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * The "others" might still include languages that appear in the "suggested" section.</p>
461808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita *
471808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * <p>Example: if we show "German Switzerland" as "suggested" (based on SIM, let's say),
481808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * then "German" will still show in the "others" section, clicking on it will only show the
491808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * countries for all the other German locales, but not Switzerland
501808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita * (Austria, Belgium, Germany, Liechtenstein, Luxembourg)</p>
511808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita */
52137b96e3a41edc19a53f7218ef3e53adbfcfd340Mihai Nitapublic class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
531808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private static final int TYPE_HEADER_SUGGESTED = 0;
541808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private static final int TYPE_HEADER_ALL_OTHERS = 1;
551808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private static final int TYPE_LOCALE = 2;
5686235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita    private static final int MIN_REGIONS_FOR_SUGGESTIONS = 6;
571808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
581808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private ArrayList<LocaleStore.LocaleInfo> mLocaleOptions;
591808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private ArrayList<LocaleStore.LocaleInfo> mOriginalLocaleOptions;
601808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private int mSuggestionCount;
611808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private final boolean mCountryMode;
621808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private LayoutInflater mInflater;
631808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
643f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader    private Locale mDisplayLocale = null;
653f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader    // used to potentially cache a modified Context that uses mDisplayLocale
663f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader    private Context mContextOverride = null;
673f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader
68137b96e3a41edc19a53f7218ef3e53adbfcfd340Mihai Nita    public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode) {
691808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        mCountryMode = countryMode;
701808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        mLocaleOptions = new ArrayList<>(localeOptions.size());
711808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        for (LocaleStore.LocaleInfo li : localeOptions) {
721808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            if (li.isSuggested()) {
731808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                mSuggestionCount++;
741808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
751808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            mLocaleOptions.add(li);
761808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
771808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
781808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
791808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
801808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public boolean areAllItemsEnabled() {
811808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        return false;
821808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
831808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
841808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
851808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public boolean isEnabled(int position) {
861808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        return getItemViewType(position) == TYPE_LOCALE;
871808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
881808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
891808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
901808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public int getItemViewType(int position) {
911808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        if (!showHeaders()) {
921808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            return TYPE_LOCALE;
931808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        } else {
941808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            if (position == 0) {
951808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                return TYPE_HEADER_SUGGESTED;
961808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
971808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            if (position == mSuggestionCount + 1) {
981808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                return TYPE_HEADER_ALL_OTHERS;
991808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
1001808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            return TYPE_LOCALE;
1011808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
1021808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
1031808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
1041808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
1051808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public int getViewTypeCount() {
1061808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        if (showHeaders()) {
1071808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            return 3; // Two headers in addition to the locales
1081808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        } else {
1091808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            return 1; // Locales items only
1101808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
1111808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
1121808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
1131808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
1141808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public int getCount() {
1151808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        if (showHeaders()) {
1161808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            return mLocaleOptions.size() + 2; // 2 extra for the headers
1171808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        } else {
1181808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            return mLocaleOptions.size();
1191808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
1201808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
1211808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
1221808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
1231808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public Object getItem(int position) {
1241808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        int offset = 0;
1251808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        if (showHeaders()) {
1261808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            offset = position > mSuggestionCount ? -2 : -1;
1271808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
1281808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
1291808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        return mLocaleOptions.get(position + offset);
1301808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
1311808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
1321808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
1331808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public long getItemId(int position) {
1341808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        return position;
1351808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
1361808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
1373f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader    /**
1383f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader     * Overrides the locale used to display localized labels. Setting the locale to null will reset
1393f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader     * the Adapter to use the default locale for the labels.
1403f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader     */
1413f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader    public void setDisplayLocale(@NonNull Context context, @Nullable Locale locale) {
1423f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader        if (locale == null) {
1433f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            mDisplayLocale = null;
1443f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            mContextOverride = null;
1453f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader        } else if (!locale.equals(mDisplayLocale)) {
1463f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            mDisplayLocale = locale;
1473f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            final Configuration configOverride = new Configuration();
1483f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            configOverride.setLocale(locale);
1493f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            mContextOverride = context.createConfigurationContext(configOverride);
1503f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader        }
1513f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader    }
1523f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader
1533f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader    private void setTextTo(@NonNull TextView textView, int resId) {
1543f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader        if (mContextOverride == null) {
1553f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            textView.setText(resId);
1563f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader        } else {
1573f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            textView.setText(mContextOverride.getText(resId));
1583f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader            // If mContextOverride is not null, mDisplayLocale can't be null either.
1593f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader        }
1603f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader    }
1613f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader
1621808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
1631808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public View getView(int position, View convertView, ViewGroup parent) {
1641808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        if (convertView == null && mInflater == null) {
1651808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            mInflater = LayoutInflater.from(parent.getContext());
1661808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
1671808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
1681808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        int itemType = getItemViewType(position);
1691808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        switch (itemType) {
1701808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            case TYPE_HEADER_SUGGESTED: // intentional fallthrough
1711808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            case TYPE_HEADER_ALL_OTHERS:
1721808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                // Covers both null, and "reusing" a wrong kind of view
1731808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                if (!(convertView instanceof TextView)) {
1741808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    convertView = mInflater.inflate(R.layout.language_picker_section_header,
1751808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                            parent, false);
1761808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                }
1771808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                TextView textView = (TextView) convertView;
1781808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                if (itemType == TYPE_HEADER_SUGGESTED) {
1793f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader                    setTextTo(textView, R.string.language_picker_section_suggested);
1801808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                } else {
181543e45babeb200a3586bbbd8ffd0b6e2f3f0687cMihai Nita                    if (mCountryMode) {
1823f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader                        setTextTo(textView, R.string.region_picker_section_all);
183543e45babeb200a3586bbbd8ffd0b6e2f3f0687cMihai Nita                    } else {
1843f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader                        setTextTo(textView, R.string.language_picker_section_all);
185543e45babeb200a3586bbbd8ffd0b6e2f3f0687cMihai Nita                    }
1861808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                }
1873f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader                textView.setTextLocale(
1883f01530a684755dbebeb15bbdb70d0b0cd11dbd0Roozbeh Pournader                        mDisplayLocale != null ? mDisplayLocale : Locale.getDefault());
1891808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                break;
1901808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            default:
1911808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                // Covers both null, and "reusing" a wrong kind of view
1921808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                if (!(convertView instanceof ViewGroup)) {
1931808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    convertView = mInflater.inflate(R.layout.language_picker_item, parent, false);
1941808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                }
1951808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
1961808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                TextView text = (TextView) convertView.findViewById(R.id.locale);
1971808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
198f1f39cf1936df2d28133e43390f72f3dbb40ffc8Mihai Nita                text.setText(item.getLabel(mCountryMode));
199502141d50bbd188a37b59f2ea9fa794a296f7247Mihai Nita                text.setTextLocale(item.getLocale());
20043af6366f2aad8c0c0a8ae1367215961ccd75c29Mihai Nita                text.setContentDescription(item.getContentDescription(mCountryMode));
20124215ecadce5f44de33959b4f512482f39ac4c92Mihai Nita                if (mCountryMode) {
20224215ecadce5f44de33959b4f512482f39ac4c92Mihai Nita                    int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
20324215ecadce5f44de33959b4f512482f39ac4c92Mihai Nita                    //noinspection ResourceType
20424215ecadce5f44de33959b4f512482f39ac4c92Mihai Nita                    convertView.setLayoutDirection(layoutDir);
20524215ecadce5f44de33959b4f512482f39ac4c92Mihai Nita                    text.setTextDirection(layoutDir == View.LAYOUT_DIRECTION_RTL
20624215ecadce5f44de33959b4f512482f39ac4c92Mihai Nita                            ? View.TEXT_DIRECTION_RTL
20724215ecadce5f44de33959b4f512482f39ac4c92Mihai Nita                            : View.TEXT_DIRECTION_LTR);
20824215ecadce5f44de33959b4f512482f39ac4c92Mihai Nita                }
2091808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
2101808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        return convertView;
2111808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
2121808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2131808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    private boolean showHeaders() {
21486235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        // We don't want to show suggestions for locales with very few regions
21586235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        // (e.g. Romanian, with 2 regions)
21686235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        // So we put a (somewhat) arbitrary limit.
21786235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        //
21886235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        // The initial idea was to make that limit dependent on the screen height.
21986235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        // But that would mean rotating the screen could make the suggestions disappear,
22086235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        // as the number of countries that fits on the screen would be different in portrait
22186235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        // and landscape mode.
22286235d497007ad17ddec7e659fb0e0c36b010745Mihai Nita        if (mCountryMode && mLocaleOptions.size() < MIN_REGIONS_FOR_SUGGESTIONS) {
223f1f39cf1936df2d28133e43390f72f3dbb40ffc8Mihai Nita            return false;
224f1f39cf1936df2d28133e43390f72f3dbb40ffc8Mihai Nita        }
2251808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        return mSuggestionCount != 0 && mSuggestionCount != mLocaleOptions.size();
2261808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
2271808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
228137b96e3a41edc19a53f7218ef3e53adbfcfd340Mihai Nita    /**
229137b96e3a41edc19a53f7218ef3e53adbfcfd340Mihai Nita     * Sorts the items in the adapter using a locale-aware comparator.
230137b96e3a41edc19a53f7218ef3e53adbfcfd340Mihai Nita     * @param comp The locale-aware comparator to use.
231137b96e3a41edc19a53f7218ef3e53adbfcfd340Mihai Nita     */
2321808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public void sort(LocaleHelper.LocaleInfoComparator comp) {
2331808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        Collections.sort(mLocaleOptions, comp);
2341808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
2351808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2361808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    class FilterByNativeAndUiNames extends Filter {
2371808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2381808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        @Override
2391808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        protected FilterResults performFiltering(CharSequence prefix) {
2401808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            FilterResults results = new FilterResults();
2411808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2421808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            if (mOriginalLocaleOptions == null) {
2431808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                mOriginalLocaleOptions = new ArrayList<>(mLocaleOptions);
2441808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
2451808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2461808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            ArrayList<LocaleStore.LocaleInfo> values;
2471808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            values = new ArrayList<>(mOriginalLocaleOptions);
2481808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            if (prefix == null || prefix.length() == 0) {
2491808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                results.values = values;
2501808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                results.count = values.size();
2511808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            } else {
2521808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                // TODO: decide if we should use the string's locale
2531808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                Locale locale = Locale.getDefault();
2541808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                String prefixString = LocaleHelper.normalizeForSearch(prefix.toString(), locale);
2551808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2561808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                final int count = values.size();
2571808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                final ArrayList<LocaleStore.LocaleInfo> newValues = new ArrayList<>();
2581808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2591808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                for (int i = 0; i < count; i++) {
2601808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    final LocaleStore.LocaleInfo value = values.get(i);
2611808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    final String nameToCheck = LocaleHelper.normalizeForSearch(
2621808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                            value.getFullNameInUiLanguage(), locale);
2631808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    final String nativeNameToCheck = LocaleHelper.normalizeForSearch(
2641808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                            value.getFullNameNative(), locale);
2651808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    if (wordMatches(nativeNameToCheck, prefixString)
2661808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                            || wordMatches(nameToCheck, prefixString)) {
2671808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                        newValues.add(value);
2681808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    }
2691808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                }
2701808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2711808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                results.values = newValues;
2721808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                results.count = newValues.size();
2731808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
2741808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2751808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            return results;
2761808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
2771808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2781808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        // TODO: decide if this is enough, or we want to use a BreakIterator...
2791808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        boolean wordMatches(String valueText, String prefixString) {
280137b96e3a41edc19a53f7218ef3e53adbfcfd340Mihai Nita            // First match against the whole, non-split value
2811808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            if (valueText.startsWith(prefixString)) {
2821808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                return true;
2831808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
2841808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2851808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            final String[] words = valueText.split(" ");
2861808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            // Start at index 0, in case valueText starts with space(s)
2871808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            for (String word : words) {
2881808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                if (word.startsWith(prefixString)) {
2891808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    return true;
2901808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                }
2911808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
2921808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2931808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            return false;
2941808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
2951808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
2961808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        @Override
2971808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        protected void publishResults(CharSequence constraint, FilterResults results) {
2981808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            mLocaleOptions = (ArrayList<LocaleStore.LocaleInfo>) results.values;
2991808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
3001808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            mSuggestionCount = 0;
3011808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            for (LocaleStore.LocaleInfo li : mLocaleOptions) {
3021808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                if (li.isSuggested()) {
3031808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                    mSuggestionCount++;
3041808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                }
3051808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
3061808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
3071808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            if (results.count > 0) {
3081808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                notifyDataSetChanged();
3091808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            } else {
3101808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita                notifyDataSetInvalidated();
3111808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita            }
3121808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        }
3131808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
3141808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita
3151808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    @Override
3161808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    public Filter getFilter() {
3171808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita        return new FilterByNativeAndUiNames();
3181808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita    }
3191808ff7cde452d4831dcfbc6b99afc57f66daedfMihai Nita}
320