1 /*
2  * Copyright (C) 2015 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.tv.settings.system;
18 
19 import android.app.ActivityManager;
20 import android.app.tvsettings.TvSettingsEnums;
21 import android.content.Context;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.RemoteException;
25 import android.util.ArrayMap;
26 import android.util.Log;
27 
28 import androidx.annotation.Keep;
29 import androidx.preference.Preference;
30 import androidx.preference.PreferenceScreen;
31 
32 import com.android.internal.app.LocalePicker;
33 import com.android.internal.logging.nano.MetricsProto;
34 import com.android.settingslib.development.DevelopmentSettingsEnabler;
35 import com.android.tv.settings.R;
36 import com.android.tv.settings.RadioPreference;
37 import com.android.tv.settings.SettingsPreferenceFragment;
38 
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Map;
42 
43 /**
44  * The language settings screen in TV Settings.
45  */
46 @Keep
47 public class LanguageFragment extends SettingsPreferenceFragment {
48     private static final String TAG = "LanguageFragment";
49 
50     // Pseudo locales used for internal purposes only should not be shown in the
51     // language picker.
52     private static final String PSEUDO_LOCALE_EN_XC = "en-XC";
53 
54     private static final String LANGUAGE_RADIO_GROUP = "language";
55 
56     private final Map<String, LocalePicker.LocaleInfo> mLocaleInfoMap = new ArrayMap<>();
57 
58     // Adjust this value to keep things relatively responsive without janking animations
59     private static final int LANGUAGE_SET_DELAY_MS = 500;
60     private final Handler mDelayHandler = new Handler();
61     private Locale mNewLocale;
62     private final Runnable mSetLanguageRunnable = new Runnable() {
63         @Override
64         public void run() {
65             LocalePicker.updateLocale(mNewLocale);
66         }
67     };
68 
newInstance()69     public static LanguageFragment newInstance() {
70         return new LanguageFragment();
71     }
72 
73     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)74     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
75         final Context themedContext = getPreferenceManager().getContext();
76         final PreferenceScreen screen =
77                 getPreferenceManager().createPreferenceScreen(themedContext);
78         screen.setTitle(R.string.system_language);
79 
80         Locale currentLocale = null;
81         try {
82             currentLocale = ActivityManager.getService().getConfiguration()
83                     .getLocales().get(0);
84         } catch (RemoteException e) {
85             Log.e(TAG, "Could not retrieve locale", e);
86         }
87 
88         final List<LocalePicker.LocaleInfo> localeInfoList =
89                 LocalePicker.getAllAssetLocales(themedContext,
90                         DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext()));
91 
92         Preference activePref = null;
93         for (final LocalePicker.LocaleInfo localeInfo : localeInfoList) {
94             final String languageTag = localeInfo.getLocale().toLanguageTag();
95             if (PSEUDO_LOCALE_EN_XC.equals(languageTag)) {
96                 continue;
97             }
98             mLocaleInfoMap.put(languageTag, localeInfo);
99 
100             final RadioPreference radioPreference = new RadioPreference(themedContext);
101             radioPreference.setKey(languageTag);
102             radioPreference.setPersistent(false);
103             radioPreference.setTitle(localeInfo.getLabel());
104             radioPreference.setRadioGroup(LANGUAGE_RADIO_GROUP);
105             radioPreference.setLayoutResource(R.layout.preference_reversed_widget);
106 
107             if (localeInfo.getLocale().equals(currentLocale)) {
108                 radioPreference.setChecked(true);
109                 activePref = radioPreference;
110             }
111 
112             screen.addPreference(radioPreference);
113         }
114 
115         if (activePref != null && savedInstanceState == null) {
116             scrollToPreference(activePref);
117         }
118 
119         setPreferenceScreen(screen);
120     }
121 
122     @Override
onPreferenceTreeClick(Preference preference)123     public boolean onPreferenceTreeClick(Preference preference) {
124         if (preference instanceof RadioPreference) {
125             final RadioPreference radioPreference = (RadioPreference) preference;
126             radioPreference.clearOtherRadioPreferences(getPreferenceScreen());
127             if (radioPreference.isChecked()) {
128                 mNewLocale = mLocaleInfoMap.get(radioPreference.getKey()).getLocale();
129                 mDelayHandler.removeCallbacks(mSetLanguageRunnable);
130                 mDelayHandler.postDelayed(mSetLanguageRunnable, LANGUAGE_SET_DELAY_MS);
131             } else {
132                 radioPreference.setChecked(true);
133             }
134         }
135         return super.onPreferenceTreeClick(preference);
136     }
137 
138     @Override
getMetricsCategory()139     public int getMetricsCategory() {
140         return MetricsProto.MetricsEvent.SETTINGS_LANGUAGE_CATEGORY;
141     }
142 
143     @Override
getPageId()144     protected int getPageId() {
145         return TvSettingsEnums.SYSTEM_LANGUAGE;
146     }
147 }
148