• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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