InputMethodAndLanguageSettings.java revision d79934731c8d33f6fc63b21c120b9ffba5d06f54
1/*
2 * Copyright (C) 2008 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
17package com.android.settings;
18
19import android.app.AlertDialog;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.Intent;
23import android.content.pm.ApplicationInfo;
24import android.content.res.Configuration;
25import android.os.Bundle;
26import android.preference.CheckBoxPreference;
27import android.preference.Preference;
28import android.preference.PreferenceGroup;
29import android.preference.PreferenceScreen;
30import android.provider.Settings;
31import android.text.TextUtils;
32import android.view.inputmethod.InputMethodInfo;
33import android.view.inputmethod.InputMethodManager;
34
35import java.util.ArrayList;
36import java.util.HashSet;
37import java.util.List;
38
39public class LanguageSettings extends SettingsPreferenceFragment {
40
41    private static final String KEY_PHONE_LANGUAGE = "phone_language";
42    private static final String KEY_INPUT_METHOD = "input_method";
43
44    private boolean mHaveHardKeyboard;
45
46    private List<InputMethodInfo> mInputMethodProperties;
47    private List<CheckBoxPreference> mCheckboxes;
48    private Preference mLanguagePref;
49
50    final TextUtils.SimpleStringSplitter mStringColonSplitter
51            = new TextUtils.SimpleStringSplitter(':');
52
53    private String mLastInputMethodId;
54    private String mLastTickedInputMethodId;
55
56    private AlertDialog mDialog = null;
57
58    static public String getInputMethodIdFromKey(String key) {
59        return key;
60    }
61
62    @Override
63    public void onCreate(Bundle icicle) {
64        super.onCreate(icicle);
65
66        addPreferencesFromResource(R.xml.language_settings);
67
68        if (getActivity().getAssets().getLocales().length == 1) {
69            getPreferenceScreen().
70                removePreference(findPreference("language_category"));
71        } else {
72            mLanguagePref = findPreference(KEY_PHONE_LANGUAGE);
73        }
74
75        Configuration config = getResources().getConfiguration();
76        if (config.keyboard != Configuration.KEYBOARD_QWERTY) {
77            getPreferenceScreen().removePreference(
78                    getPreferenceScreen().findPreference("hardkeyboard_category"));
79        } else {
80            mHaveHardKeyboard = true;
81        }
82        mCheckboxes = new ArrayList<CheckBoxPreference>();
83        onCreateIMM();
84    }
85
86    private boolean isSystemIme(InputMethodInfo property) {
87        return (property.getServiceInfo().applicationInfo.flags
88                & ApplicationInfo.FLAG_SYSTEM) != 0;
89    }
90
91    private void onCreateIMM() {
92        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
93
94        mInputMethodProperties = imm.getInputMethodList();
95
96        mLastInputMethodId = Settings.Secure.getString(getContentResolver(),
97            Settings.Secure.DEFAULT_INPUT_METHOD);
98
99        PreferenceGroup textCategory = (PreferenceGroup) findPreference("text_category");
100
101        int N = (mInputMethodProperties == null ? 0 : mInputMethodProperties
102                .size());
103        for (int i = 0; i < N; ++i) {
104            InputMethodInfo property = mInputMethodProperties.get(i);
105            String prefKey = property.getId();
106
107            CharSequence label = property.loadLabel(getActivity().getPackageManager());
108            boolean systemIME = isSystemIme(property);
109            // Add a check box.
110            // Don't show the toggle if it's the only keyboard in the system, or it's a system IME.
111            if (mHaveHardKeyboard || (N > 1 && !systemIME)) {
112                CheckBoxPreference chkbxPref = new CheckBoxPreference(getActivity());
113                chkbxPref.setKey(prefKey);
114                chkbxPref.setTitle(label);
115                textCategory.addPreference(chkbxPref);
116                mCheckboxes.add(chkbxPref);
117            }
118
119            // If setting activity is available, add a setting screen entry.
120            if (null != property.getSettingsActivity()) {
121                PreferenceScreen prefScreen = new PreferenceScreen(getActivity(), null);
122                String settingsActivity = property.getSettingsActivity();
123                if (settingsActivity.lastIndexOf("/") < 0) {
124                    settingsActivity = property.getPackageName() + "/" + settingsActivity;
125                }
126                prefScreen.setKey(settingsActivity);
127                prefScreen.setTitle(label);
128                if (N == 1) {
129                    prefScreen.setSummary(getResources().getString(
130                            R.string.onscreen_keyboard_settings_summary));
131                } else {
132                    CharSequence settingsLabel = getResources().getString(
133                            R.string.input_methods_settings_label_format, label);
134                    prefScreen.setSummary(settingsLabel);
135                }
136                textCategory.addPreference(prefScreen);
137            }
138        }
139    }
140
141    @Override
142    public void onResume() {
143        super.onResume();
144
145        final HashSet<String> enabled = new HashSet<String>();
146        String enabledStr = Settings.Secure.getString(getContentResolver(),
147                Settings.Secure.ENABLED_INPUT_METHODS);
148        if (enabledStr != null) {
149            final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
150            splitter.setString(enabledStr);
151            while (splitter.hasNext()) {
152                enabled.add(splitter.next());
153            }
154        }
155
156        // Update the statuses of the Check Boxes.
157        int N = mInputMethodProperties.size();
158        for (int i = 0; i < N; ++i) {
159            final String id = mInputMethodProperties.get(i).getId();
160            CheckBoxPreference pref = (CheckBoxPreference) findPreference(mInputMethodProperties
161                    .get(i).getId());
162            if (pref != null) {
163                pref.setChecked(enabled.contains(id));
164            }
165        }
166        mLastTickedInputMethodId = null;
167
168        if (mLanguagePref != null) {
169            Configuration conf = getResources().getConfiguration();
170            String locale = conf.locale.getDisplayName(conf.locale);
171            if (locale != null && locale.length() > 1) {
172                locale = Character.toUpperCase(locale.charAt(0)) + locale.substring(1);
173                mLanguagePref.setSummary(locale);
174            }
175        }
176    }
177
178    @Override
179    public void onPause() {
180        super.onPause();
181
182        StringBuilder builder = new StringBuilder(256);
183        StringBuilder disabledSysImes = new StringBuilder(256);
184
185        int firstEnabled = -1;
186        int N = mInputMethodProperties.size();
187        for (int i = 0; i < N; ++i) {
188            final InputMethodInfo property = mInputMethodProperties.get(i);
189            final String id = property.getId();
190            CheckBoxPreference pref = (CheckBoxPreference) findPreference(id);
191            boolean hasIt = id.equals(mLastInputMethodId);
192            boolean systemIme = isSystemIme(property);
193            if (((N == 1 || systemIme) && !mHaveHardKeyboard)
194                    || (pref != null && pref.isChecked())) {
195                if (builder.length() > 0) builder.append(':');
196                builder.append(id);
197                if (firstEnabled < 0) {
198                    firstEnabled = i;
199                }
200            } else if (hasIt) {
201                mLastInputMethodId = mLastTickedInputMethodId;
202            }
203            // If it's a disabled system ime, add it to the disabled list so that it
204            // doesn't get enabled automatically on any changes to the package list
205            if (pref != null && !pref.isChecked() && systemIme && mHaveHardKeyboard) {
206                if (disabledSysImes.length() > 0) disabledSysImes.append(":");
207                disabledSysImes.append(id);
208            }
209        }
210
211        // If the last input method is unset, set it as the first enabled one.
212        if (null == mLastInputMethodId || "".equals(mLastInputMethodId)) {
213            if (firstEnabled >= 0) {
214                mLastInputMethodId = mInputMethodProperties.get(firstEnabled).getId();
215            } else {
216                mLastInputMethodId = null;
217            }
218        }
219
220        Settings.Secure.putString(getContentResolver(),
221            Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
222        Settings.Secure.putString(getContentResolver(),
223                Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, disabledSysImes.toString());
224        Settings.Secure.putString(getContentResolver(),
225            Settings.Secure.DEFAULT_INPUT_METHOD,
226            mLastInputMethodId != null ? mLastInputMethodId : "");
227    }
228
229    @Override
230    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
231
232        // Input Method stuff
233        if (Utils.isMonkeyRunning()) {
234            return false;
235        }
236
237        if (preference instanceof CheckBoxPreference) {
238            final CheckBoxPreference chkPref = (CheckBoxPreference) preference;
239            final String id = getInputMethodIdFromKey(chkPref.getKey());
240            if (chkPref.isChecked()) {
241                InputMethodInfo selImi = null;
242                final int N = mInputMethodProperties.size();
243                for (int i=0; i<N; i++) {
244                    InputMethodInfo imi = mInputMethodProperties.get(i);
245                    if (id.equals(imi.getId())) {
246                        selImi = imi;
247                        if (isSystemIme(imi)) {
248                            // This is a built-in IME, so no need to warn.
249                            mLastTickedInputMethodId = id;
250                            return super.onPreferenceTreeClick(preferenceScreen, preference);
251                        }
252                    }
253                }
254                chkPref.setChecked(false);
255                if (selImi == null) {
256                    return super.onPreferenceTreeClick(preferenceScreen, preference);
257                }
258                if (mDialog == null) {
259                    // TODO: DialogFragment?
260                    mDialog = (new AlertDialog.Builder(getActivity()))
261                            .setTitle(android.R.string.dialog_alert_title)
262                            .setIcon(android.R.drawable.ic_dialog_alert)
263                            .setCancelable(true)
264                            .setPositiveButton(android.R.string.ok,
265                                    new DialogInterface.OnClickListener() {
266                                        public void onClick(DialogInterface dialog, int which) {
267                                            chkPref.setChecked(true);
268                                            mLastTickedInputMethodId = id;
269                                        }
270
271                            })
272                            .setNegativeButton(android.R.string.cancel,
273                                    new DialogInterface.OnClickListener() {
274                                        public void onClick(DialogInterface dialog, int which) {
275                                        }
276
277                            })
278                            .create();
279                } else {
280                    if (mDialog.isShowing()) {
281                        mDialog.dismiss();
282                    }
283                }
284                mDialog.setMessage(getResources().getString(
285                        R.string.ime_security_warning,
286                        selImi.getServiceInfo().applicationInfo.loadLabel(getPackageManager())));
287                mDialog.show();
288            } else if (id.equals(mLastTickedInputMethodId)) {
289                mLastTickedInputMethodId = null;
290            }
291        } else if (preference instanceof PreferenceScreen) {
292            if (KEY_INPUT_METHOD.equals(preference.getKey())) {
293                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
294                imm.showInputMethodPicker();
295            } else if (preference.getIntent() == null) {
296                PreferenceScreen pref = (PreferenceScreen) preference;
297                String activityName = pref.getKey();
298                String packageName = activityName.substring(0, activityName
299                        .lastIndexOf("."));
300                int slash = activityName.indexOf("/");
301                if (slash > 0) {
302                    packageName = activityName.substring(0, slash);
303                    activityName = activityName.substring(slash + 1);
304                }
305                if (activityName.length() > 0) {
306                    Intent i = new Intent(Intent.ACTION_MAIN);
307                    i.setClassName(packageName, activityName);
308                    startActivity(i);
309                }
310            }
311        }
312        return super.onPreferenceTreeClick(preferenceScreen, preference);
313    }
314
315    @Override
316    public void onDestroy() {
317        super.onDestroy();
318        if (mDialog != null) {
319            mDialog.dismiss();
320            mDialog = null;
321        }
322    }
323
324}
325