1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.settings.system; 18 19 import android.arch.lifecycle.LiveData; 20 import android.arch.lifecycle.MutableLiveData; 21 import android.arch.lifecycle.ViewModel; 22 import android.arch.lifecycle.ViewModelProviders; 23 import android.content.Context; 24 import android.content.res.Configuration; 25 import android.content.res.Resources; 26 import android.os.AsyncTask; 27 import android.os.Build; 28 import android.os.Bundle; 29 30 import androidx.car.widget.ListItemProvider; 31 32 import com.android.car.settings.R; 33 import com.android.car.settings.common.ListItemSettingsFragment; 34 import com.android.car.settingslib.language.LanguagePickerUtils; 35 import com.android.car.settingslib.language.LocaleListItemProvider; 36 import com.android.car.settingslib.language.LocaleSelectionListener; 37 import com.android.internal.app.LocalePicker; 38 import com.android.internal.app.LocaleStore; 39 40 import java.util.HashSet; 41 import java.util.Locale; 42 import java.util.Set; 43 44 /** 45 * Fragment for showing the list of languages. 46 */ 47 public class LanguagePickerFragment extends ListItemSettingsFragment implements 48 LocaleSelectionListener { 49 50 private LocaleListItemProvider mLocaleListItemProvider; 51 private final HashSet<String> mLangTagsToIgnore = new HashSet<>(); 52 53 /** 54 * Factory method for creating LanguagePickerFragment. 55 */ 56 public static LanguagePickerFragment newInstance() { 57 LanguagePickerFragment LanguagePickerFragment = new LanguagePickerFragment(); 58 Bundle bundle = ListItemSettingsFragment.getBundle(); 59 bundle.putInt(EXTRA_TITLE_ID, R.string.language_settings); 60 bundle.putInt(EXTRA_ACTION_BAR_LAYOUT, R.layout.action_bar); 61 LanguagePickerFragment.setArguments(bundle); 62 return LanguagePickerFragment; 63 } 64 65 @Override 66 public void onActivityCreated(Bundle savedInstanceState) { 67 super.onActivityCreated(savedInstanceState); 68 69 LocaleViewModel viewModel = getLocaleViewModel(); 70 viewModel.getLocaleInfos(getContext(), mLangTagsToIgnore).observe(this, 71 localeInfos -> resetLocaleList(localeInfos)); 72 } 73 74 @Override 75 public ListItemProvider getItemProvider() { 76 if (mLocaleListItemProvider == null) { 77 mLocaleListItemProvider = new LocaleListItemProvider( 78 getContext(), 79 new HashSet<LocaleStore.LocaleInfo>(), 80 /* localeSelectionListener= */ this, 81 mLangTagsToIgnore); 82 } 83 return mLocaleListItemProvider; 84 } 85 86 @Override 87 public void onLocaleSelected(LocaleStore.LocaleInfo localeInfo) { 88 if (localeInfo == null || localeInfo.getLocale() == null) { 89 return; 90 } 91 92 Locale locale = localeInfo.getLocale(); 93 94 Resources res = getResources(); 95 Configuration baseConfig = res.getConfiguration(); 96 Configuration config = new Configuration(baseConfig); 97 config.setLocale(locale); 98 res.updateConfiguration(config, null); 99 100 // Apply locale to system. 101 LocalePicker.updateLocale(locale); 102 getFragmentController().goBack(); 103 } 104 105 @Override 106 public void onParentWithChildrenLocaleSelected(LocaleStore.LocaleInfo localeInfo) { 107 if (localeInfo != null) { 108 setTitle(localeInfo.getFullNameNative()); 109 refreshList(); 110 } 111 } 112 113 @Override 114 protected void onBackPressed() { 115 if (isChildLocaleDisplayed()) { 116 setTitle(getString(R.string.language_settings)); 117 getLocaleViewModel().reloadLocales(getContext(), mLangTagsToIgnore); 118 } else { 119 super.onBackPressed(); 120 } 121 } 122 123 private LocaleViewModel getLocaleViewModel() { 124 return ViewModelProviders.of(this).get(LocaleViewModel.class); 125 } 126 127 private boolean isChildLocaleDisplayed() { 128 return mLocaleListItemProvider != null && mLocaleListItemProvider.isChildLocale(); 129 } 130 131 /** 132 * Add a pseudo locale in debug build for testing RTL. 133 * 134 * @param localeInfos the set of {@link LocaleStore.LocaleInfo} to which the locale is added. 135 */ 136 private void maybeAddPseudoLocale(Set<LocaleStore.LocaleInfo> localeInfos) { 137 if (Build.IS_USERDEBUG) { 138 // The ar-XB pseudo-locale is RTL. 139 localeInfos.add(LocaleStore.getLocaleInfo(new Locale("ar", "XB"))); 140 } 141 } 142 143 private void resetLocaleList(Set<LocaleStore.LocaleInfo> localeInfos) { 144 if (mLocaleListItemProvider != null) { 145 maybeAddPseudoLocale(localeInfos); 146 mLocaleListItemProvider.updateSuggestedLocaleAdapter( 147 LanguagePickerUtils.createSuggestedLocaleAdapter( 148 getContext(), localeInfos, /* parent= */ null), 149 /* isChildLocale= */ false); 150 refreshList(); 151 } 152 } 153 154 /** 155 * ViewModel for holding the LocaleInfos. 156 */ 157 public static class LocaleViewModel extends ViewModel { 158 159 private MutableLiveData<Set<LocaleStore.LocaleInfo>> mLocaleInfos; 160 161 /** 162 * Returns LiveData holding a set of LocaleInfo. 163 */ 164 public LiveData<Set<LocaleStore.LocaleInfo>> getLocaleInfos(Context context, 165 Set<String> ignorables) { 166 167 if (mLocaleInfos == null) { 168 mLocaleInfos = new MutableLiveData<Set<LocaleStore.LocaleInfo>>(); 169 reloadLocales(context, ignorables); 170 } 171 return mLocaleInfos; 172 } 173 174 /** 175 * Reload the locales based on the current context. 176 */ 177 public void reloadLocales(Context context, Set<String> ignorables) { 178 new AsyncTask<Context, Void, Set<LocaleStore.LocaleInfo>>() { 179 @Override 180 protected Set<LocaleStore.LocaleInfo> doInBackground(Context... contexts) { 181 return LocaleStore.getLevelLocales( 182 contexts[0], 183 ignorables, 184 /* parent= */ null, 185 /* translatedOnly= */ true); 186 } 187 188 @Override 189 protected void onPostExecute(Set<LocaleStore.LocaleInfo> localeInfos) { 190 LocaleViewModel.this.mLocaleInfos.setValue(localeInfos); 191 } 192 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, context); 193 } 194 } 195 } 196