1 /** 2 * Copyright (C) 2025 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.settings.localepicker; 18 19 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_APPS_LOCALE; 20 21 import android.app.Activity; 22 import android.app.settings.SettingsEnums; 23 import android.content.Context; 24 import android.util.ArrayMap; 25 import android.util.Log; 26 27 import androidx.annotation.NonNull; 28 import androidx.annotation.Nullable; 29 import androidx.annotation.VisibleForTesting; 30 import androidx.core.app.NotificationCompat; 31 import androidx.preference.Preference; 32 import androidx.preference.PreferenceCategory; 33 import androidx.preference.PreferenceScreen; 34 35 import com.android.internal.app.AppLocaleCollector; 36 import com.android.internal.app.LocaleStore; 37 import com.android.settings.R; 38 import com.android.settings.applications.manageapplications.ManageApplicationsUtil; 39 import com.android.settings.core.BasePreferenceController; 40 import com.android.settingslib.widget.SelectorWithWidgetPreference; 41 42 import java.util.ArrayList; 43 import java.util.List; 44 import java.util.Map; 45 import java.util.Set; 46 import java.util.stream.Collectors; 47 48 /** A controller for handling suggested locale of app. */ 49 public class AppLocaleSuggestedListPreferenceController extends 50 BasePreferenceController implements LocaleListSearchCallback { 51 private static final String TAG = "AppLocaleSuggestedListPreferenceController"; 52 private static final String KEY_PREFERENCE_CATEGORY_APP_LANGUAGE_SUGGESTED = 53 "app_language_suggested_category"; 54 private static final String KEY_PREFERENCE_APP_LOCALE_SUGGESTED_LIST = 55 "app_locale_suggested_list"; 56 private static final String KEY_PREFERENCE_CATEGORY_ADD_A_LANGUAGE_SUGGESTED = 57 "system_language_suggested_category"; 58 59 private Activity mActivity; 60 @SuppressWarnings("NullAway") 61 private PreferenceCategory mPreferenceCategory; 62 private Set<LocaleStore.LocaleInfo> mLocaleList; 63 private List<LocaleStore.LocaleInfo> mLocaleOptions; 64 private Map<String, Preference> mSuggestedPreferences; 65 private boolean mIsCountryMode; 66 @Nullable private LocaleStore.LocaleInfo mParentLocale; 67 private AppLocaleCollector mAppLocaleCollector; 68 @SuppressWarnings("NullAway") 69 private String mPackageName; 70 private boolean mIsNumberingSystemMode; 71 72 @SuppressWarnings("NullAway") AppLocaleSuggestedListPreferenceController(@onNull Context context, @NonNull String preferenceKey)73 public AppLocaleSuggestedListPreferenceController(@NonNull Context context, 74 @NonNull String preferenceKey) { 75 super(context, preferenceKey); 76 } 77 78 @SuppressWarnings("NullAway") AppLocaleSuggestedListPreferenceController(@onNull Context context, @NonNull String preferenceKey, @Nullable String packageName, boolean isNumberingSystemMode, @NonNull LocaleStore.LocaleInfo parentLocale, @NonNull Activity activity, @NonNull AppLocaleCollector appLocaleCollector)79 public AppLocaleSuggestedListPreferenceController(@NonNull Context context, 80 @NonNull String preferenceKey, @Nullable String packageName, 81 boolean isNumberingSystemMode, @NonNull LocaleStore.LocaleInfo parentLocale, 82 @NonNull Activity activity, @NonNull AppLocaleCollector appLocaleCollector) { 83 super(context, preferenceKey); 84 mPackageName = packageName; 85 mIsNumberingSystemMode = isNumberingSystemMode; 86 mParentLocale = parentLocale; 87 mIsCountryMode = mParentLocale != null; 88 mActivity = activity; 89 mAppLocaleCollector = appLocaleCollector; 90 } 91 92 @Override displayPreference(@onNull PreferenceScreen screen)93 public void displayPreference(@NonNull PreferenceScreen screen) { 94 super.displayPreference(screen); 95 mPreferenceCategory = screen.findPreference( 96 (mIsNumberingSystemMode || mIsCountryMode) 97 ? KEY_PREFERENCE_CATEGORY_ADD_A_LANGUAGE_SUGGESTED 98 : KEY_PREFERENCE_CATEGORY_APP_LANGUAGE_SUGGESTED); 99 100 mSuggestedPreferences = new ArrayMap<>(); 101 mLocaleOptions = new ArrayList<>(); 102 updatePreferences(); 103 } 104 updatePreferences()105 private void updatePreferences() { 106 if (mPreferenceCategory == null) { 107 Log.d(TAG, "updatePreferences, mPreferenceCategory is null"); 108 return; 109 } 110 111 List<LocaleStore.LocaleInfo> result = LocaleUtils.getSortedLocaleList( 112 getSuggestedLocaleList(), mIsCountryMode); 113 final Map<String, Preference> existingSuggestedPreferences = mSuggestedPreferences; 114 mSuggestedPreferences = new ArrayMap<>(); 115 setupSuggestedPreference(result, existingSuggestedPreferences); 116 for (Preference pref : existingSuggestedPreferences.values()) { 117 mPreferenceCategory.removePreference(pref); 118 } 119 } 120 121 @Override onSearchListChanged(@onNull List<LocaleStore.LocaleInfo> newList, @Nullable CharSequence prefix)122 public void onSearchListChanged(@NonNull List<LocaleStore.LocaleInfo> newList, 123 @Nullable CharSequence prefix) { 124 if (mPreferenceCategory == null) { 125 Log.d(TAG, "onSearchListChanged, mPreferenceCategory is null"); 126 return; 127 } 128 129 mPreferenceCategory.removeAll(); 130 final Map<String, Preference> existingSuggestedPreferences = mSuggestedPreferences; 131 List<LocaleStore.LocaleInfo> sortedList = getSuggestedLocaleList(); 132 newList = LocaleUtils.getSortedLocaleFromSearchList(newList, sortedList, mIsCountryMode); 133 setupSuggestedPreference(newList, existingSuggestedPreferences); 134 } 135 136 @VisibleForTesting setupSuggestedPreference(List<LocaleStore.LocaleInfo> localeInfoList, Map<String, Preference> existingSuggestedPreferences)137 void setupSuggestedPreference(List<LocaleStore.LocaleInfo> localeInfoList, 138 Map<String, Preference> existingSuggestedPreferences) { 139 for (LocaleStore.LocaleInfo locale : localeInfoList) { 140 if (mIsNumberingSystemMode || mIsCountryMode) { 141 Preference pref = existingSuggestedPreferences.remove(locale.getId()); 142 if (pref == null) { 143 pref = new Preference(mContext); 144 setupPreference(pref, locale); 145 mPreferenceCategory.addPreference(pref); 146 } 147 } else { 148 SelectorWithWidgetPreference pref = 149 (SelectorWithWidgetPreference) existingSuggestedPreferences.remove( 150 locale.getId()); 151 if (pref == null) { 152 pref = new SelectorWithWidgetPreference(mContext); 153 setupPreference(pref, locale); 154 mPreferenceCategory.addPreference(pref); 155 } 156 } 157 } 158 Log.d(TAG, "setupSuggestedPreference, mPreferenceCategory setVisible = " 159 + (mPreferenceCategory.getPreferenceCount() > 0)); 160 mPreferenceCategory.setVisible(mPreferenceCategory.getPreferenceCount() > 0); 161 } 162 setupPreference(Preference pref, LocaleStore.LocaleInfo locale)163 private void setupPreference(Preference pref, LocaleStore.LocaleInfo locale) { 164 String localeName = mIsCountryMode ? locale.getFullCountryNameNative() 165 : locale.getFullNameNative(); 166 if (pref instanceof SelectorWithWidgetPreference) { 167 ((SelectorWithWidgetPreference) pref).setChecked(locale.isAppCurrentLocale()); 168 } 169 pref.setTitle(locale.isSystemLocale() 170 ? mContext.getString(R.string.preference_of_system_locale_summary) 171 : localeName); 172 pref.setKey(locale.toString()); 173 pref.setOnPreferenceClickListener(clickedPref -> { 174 LocaleUtils.onLocaleSelected(mContext, locale, mPackageName); 175 mActivity.finish(); 176 return true; 177 }); 178 mSuggestedPreferences.put(locale.getId(), pref); 179 } 180 181 @Override getAvailabilityStatus()182 public int getAvailabilityStatus() { 183 return AVAILABLE; 184 } 185 getSuggestedLocaleList()186 protected List<LocaleStore.LocaleInfo> getSuggestedLocaleList() { 187 setupLocaleList(); 188 if (mLocaleList != null && !mLocaleList.isEmpty()) { 189 mLocaleOptions.addAll( 190 mLocaleList.stream().filter(localeInfo -> (localeInfo.isSuggested())).collect( 191 Collectors.toList())); 192 } else { 193 Log.d(TAG, "Can not get suggested locales because the locale list is null or empty."); 194 } 195 return mLocaleOptions; 196 } 197 setupLocaleList()198 private void setupLocaleList() { 199 mLocaleList = mAppLocaleCollector.getSupportedLocaleList(mParentLocale, 200 false, mIsCountryMode); 201 mLocaleOptions.clear(); 202 } 203 204 @Override getPreferenceKey()205 public @NonNull String getPreferenceKey() { 206 return KEY_PREFERENCE_APP_LOCALE_SUGGESTED_LIST; 207 } 208 } 209