/* * Copyright (C) 2018 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.car.settings.language; import android.content.Context; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceGroup; import com.android.car.settings.R; import com.android.car.settings.common.Logger; import com.android.car.settings.common.PreferenceUtil; import com.android.car.ui.preference.CarUiPreference; import com.android.internal.app.LocaleHelper; import com.android.internal.app.LocaleStore; import com.android.internal.app.SuggestedLocaleAdapter; import java.util.Locale; import java.util.Set; /** * Provides a wrapper around the {@link SuggestedLocaleAdapter} to create Preferences to populate * the Language Settings screen. */ public class LocalePreferenceProvider { private static final Logger LOG = new Logger(LanguagePickerPreferenceController.class); /** Creates a new instance of the preference provider. */ public static LocalePreferenceProvider newInstance(Context context, Set localeInfoSet, @Nullable LocaleStore.LocaleInfo parentLocale) { SuggestedLocaleAdapter adapter = createSuggestedLocaleAdapter(context, localeInfoSet, parentLocale); return new LocalePreferenceProvider(context, adapter); } /** * Header types are copied from {@link SuggestedLocaleAdapter} in order to be able to * determine the header rows. */ @VisibleForTesting static final int TYPE_HEADER_SUGGESTED = 0; @VisibleForTesting static final int TYPE_HEADER_ALL_OTHERS = 1; @VisibleForTesting static final int TYPE_LOCALE = 2; private final Context mContext; private SuggestedLocaleAdapter mSuggestedLocaleAdapter; @VisibleForTesting LocalePreferenceProvider(Context context, SuggestedLocaleAdapter localeAdapter) { mContext = context; mSuggestedLocaleAdapter = localeAdapter; } /** * Populates the base preference group based on the hierarchy provided by this provider. * * @param base the preference container which will hold the language preferences created by * this provider * @param listener the click listener registered to the language/locale preferences contained in * the base preference group */ public void populateBasePreference(PreferenceGroup base, Set ignorables, Preference.OnPreferenceClickListener listener) { /* * LocalePreferenceProvider can give elements to be represented in 2 ways. In the first * way, it simply provides the LocalePreferences which lists the available options. In the * second way, this provider may also provide PreferenceCategories to break up the * options into "Suggested" and "All others". The screen is constructed by taking a look * at the type of Preference that is provided through LocalePreferenceProvider. * * In the first case (no subcategories), preferences are added directly to the base * container. Otherwise, elements are added to the last category that was provided * (stored in "category"). */ PreferenceCategory category = null; for (int position = 0; position < mSuggestedLocaleAdapter.getCount(); position++) { Preference preference = getPreference(position, ignorables); if (PreferenceUtil.checkPreferenceType(preference, PreferenceCategory.class)) { category = (PreferenceCategory) preference; base.addPreference(category); } else { preference.setOnPreferenceClickListener(listener); if (category == null) { base.addPreference(preference); } else { category.addPreference(preference); } } } } /** * Constructs a PreferenceCategory or Preference with locale arguments based on the type of item * provided. */ private Preference getPreference(int position, Set ignorables) { int type = mSuggestedLocaleAdapter.getItemViewType(position); switch (type) { case TYPE_HEADER_SUGGESTED: case TYPE_HEADER_ALL_OTHERS: PreferenceCategory category = new PreferenceCategory(mContext); category.setTitle(type == TYPE_HEADER_SUGGESTED ? R.string.language_picker_list_suggested_header : R.string.language_picker_list_all_header); return category; case TYPE_LOCALE: LocaleStore.LocaleInfo info = (LocaleStore.LocaleInfo) mSuggestedLocaleAdapter.getItem(position); CarUiPreference preference = new CarUiPreference(mContext); preference.setTitle(info.getFullNameNative()); // Only locales with multiple sublocales needs to show the chevron, since in those // cases, the user needs to navigate to the child fragment to select the sublocale. Set subLocales = LocaleStore.getLevelLocales( mContext, ignorables, info, /* translatedOnly */ true); preference.setShowChevron(subLocales.size() > 1); LocaleUtil.setLocaleArgument(preference, info); return preference; default: LOG.d("Attempting to get unknown type: " + type); throw new IllegalStateException("Unknown locale list item type"); } } /** * Creates an instance of {@link SuggestedLocaleAdapter} with a locale * {@link LocaleStore.LocaleInfo} that is scoped to a parent locale if a parent locale is * provided. */ private static SuggestedLocaleAdapter createSuggestedLocaleAdapter(Context context, Set localeInfoSet, @Nullable LocaleStore.LocaleInfo parent) { boolean countryMode = (parent != null); Locale displayLocale = countryMode ? parent.getLocale() : Locale.getDefault(); SuggestedLocaleAdapter adapter = new SuggestedLocaleAdapter(localeInfoSet, countryMode); LocaleHelper.LocaleInfoComparator comp = new LocaleHelper.LocaleInfoComparator(displayLocale, countryMode); adapter.sort(comp); adapter.setDisplayLocale(context, displayLocale); return adapter; } }