From 4a5f889f80b683446e498f244d0eadfd979ca5d0 Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 26 Oct 2010 18:58:09 +0900 Subject: [PATCH] Copy InputMethodSubtypeEnabler from the framework - TODO: remove InputMethodSubtypeEnabler from the framework Change-Id: I751f3c73197c855c7f186ff64465d88ed1e2b603 --- AndroidManifest.xml | 13 + res/values/strings.xml | 4 + .../InputMethodAndSubtypeEnabler.java | 319 ++++++++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 src/com/android/settings/InputMethodAndSubtypeEnabler.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b7978aae58f..6a773a4bcf7 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -262,6 +262,19 @@ + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 5e46158c3c0..d6221fe0480 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2177,6 +2177,10 @@ found in the list of installed applications. Manage text input options %1$s settings + + Manage Input Methods + + Manage input methods in %1$s Onscreen keyboard settings diff --git a/src/com/android/settings/InputMethodAndSubtypeEnabler.java b/src/com/android/settings/InputMethodAndSubtypeEnabler.java new file mode 100644 index 00000000000..81116ce5935 --- /dev/null +++ b/src/com/android/settings/InputMethodAndSubtypeEnabler.java @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; +import android.preference.PreferenceScreen; +import android.provider.Settings; +import android.text.TextUtils; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment { + + private boolean mHaveHardKeyboard; + + private List mInputMethodProperties; + + private final TextUtils.SimpleStringSplitter mStringColonSplitter + = new TextUtils.SimpleStringSplitter(':'); + + private String mLastInputMethodId; + private String mLastTickedInputMethodId; + + private AlertDialog mDialog = null; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + Configuration config = getResources().getConfiguration(); + mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY); + onCreateIMM(); + setPreferenceScreen(createPreferenceHierarchy()); + } + + @Override + public void onResume() { + super.onResume(); + loadInputMethodSubtypeList(); + } + + @Override + public void onPause() { + super.onPause(); + saveInputMethodSubtypeList(); + } + + @Override + public boolean onPreferenceTreeClick( + PreferenceScreen preferenceScreen, Preference preference) { + + if (preference instanceof CheckBoxPreference) { + final CheckBoxPreference chkPref = (CheckBoxPreference) preference; + final String id = chkPref.getKey(); + // TODO: Check subtype or not here + if (chkPref.isChecked()) { + InputMethodInfo selImi = null; + final int N = mInputMethodProperties.size(); + for (int i = 0; i < N; i++) { + InputMethodInfo imi = mInputMethodProperties.get(i); + if (id.equals(imi.getId())) { + selImi = imi; + if (isSystemIme(imi)) { + setSubtypesPreferenceEnabled(id, true); + // This is a built-in IME, so no need to warn. + mLastTickedInputMethodId = id; + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + break; + } + } + if (selImi == null) { + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + chkPref.setChecked(false); + if (mDialog == null) { + mDialog = (new AlertDialog.Builder(getActivity())) + .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setCancelable(true) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + chkPref.setChecked(true); + setSubtypesPreferenceEnabled(id, true); + mLastTickedInputMethodId = id; + } + + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + } + + }) + .create(); + } else { + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + } + mDialog.setMessage(getResources().getString( + R.string.ime_security_warning, + selImi.getServiceInfo().applicationInfo.loadLabel(getPackageManager()))); + mDialog.show(); + } else { + if (id.equals(mLastTickedInputMethodId)) { + mLastTickedInputMethodId = null; + } + setSubtypesPreferenceEnabled(id, false); + } + } + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + } + + private void onCreateIMM() { + InputMethodManager imm = (InputMethodManager) getSystemService( + Context.INPUT_METHOD_SERVICE); + + // TODO: Change mInputMethodProperties to Map + mInputMethodProperties = imm.getInputMethodList(); + + mLastInputMethodId = Settings.Secure.getString(getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD); + } + + private PreferenceScreen createPreferenceHierarchy() { + // Root + PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity()); + + int N = (mInputMethodProperties == null ? 0 : mInputMethodProperties.size()); + // TODO: Use iterator. + for (int i = 0; i < N; ++i) { + PreferenceCategory keyboardSettingsCategory = new PreferenceCategory(getActivity()); + root.addPreference(keyboardSettingsCategory); + InputMethodInfo property = mInputMethodProperties.get(i); + String prefKey = property.getId(); + + PackageManager pm = getPackageManager(); + CharSequence label = property.loadLabel(pm); + boolean systemIME = isSystemIme(property); + + keyboardSettingsCategory.setTitle(label); + + // Add a check box. + // Don't show the toggle if it's the only keyboard in the system, or it's a system IME. + if (mHaveHardKeyboard || (N > 1 && !systemIME)) { + CheckBoxPreference chkbxPref = new CheckBoxPreference(getActivity()); + chkbxPref.setKey(prefKey); + chkbxPref.setTitle(label); + keyboardSettingsCategory.addPreference(chkbxPref); + } + + ArrayList subtypes = property.getSubtypes(); + if (subtypes.size() > 0) { + PreferenceCategory subtypesCategory = new PreferenceCategory(getActivity()); + subtypesCategory.setTitle(getResources().getString( + R.string.input_methods_and_subtype_enabler_title_format, label)); + root.addPreference(subtypesCategory); + for (InputMethodSubtype subtype: subtypes) { + CharSequence subtypeLabel; + int nameResId = subtype.getNameResId(); + if (nameResId != 0) { + subtypeLabel = pm.getText(property.getPackageName(), nameResId, + property.getServiceInfo().applicationInfo); + } else { + int modeResId = subtype.getModeResId(); + CharSequence language = subtype.getLocale(); + CharSequence mode = modeResId == 0 ? null + : pm.getText(property.getPackageName(), modeResId, + property.getServiceInfo().applicationInfo); + // TODO: Use more friendly Title and UI + subtypeLabel = (mode == null ? "" : mode) + "," + + (language == null ? "" : language); + } + CheckBoxPreference chkbxPref = new CheckBoxPreference(getActivity()); + chkbxPref.setKey(prefKey + subtype.hashCode()); + chkbxPref.setTitle(subtypeLabel); + chkbxPref.setSummary(label); + subtypesCategory.addPreference(chkbxPref); + } + } + } + return root; + } + + private void loadInputMethodSubtypeList() { + final HashSet enabled = new HashSet(); + String enabledStr = Settings.Secure.getString(getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS); + if (enabledStr != null) { + final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + splitter.setString(enabledStr); + while (splitter.hasNext()) { + enabled.add(splitter.next()); + } + } + + // Update the statuses of the Check Boxes. + int N = mInputMethodProperties.size(); + // TODO: Use iterator. + for (int i = 0; i < N; ++i) { + final String id = mInputMethodProperties.get(i).getId(); + CheckBoxPreference pref = (CheckBoxPreference) findPreference( + mInputMethodProperties.get(i).getId()); + if (pref != null) { + boolean isEnabled = enabled.contains(id); + pref.setChecked(isEnabled); + setSubtypesPreferenceEnabled(id, isEnabled); + } + } + mLastTickedInputMethodId = null; + } + + private void saveInputMethodSubtypeList() { + StringBuilder builder = new StringBuilder(); + StringBuilder disabledSysImes = new StringBuilder(); + + int firstEnabled = -1; + int N = mInputMethodProperties.size(); + for (int i = 0; i < N; ++i) { + final InputMethodInfo property = mInputMethodProperties.get(i); + final String id = property.getId(); + CheckBoxPreference pref = (CheckBoxPreference) findPreference(id); + boolean currentInputMethod = id.equals(mLastInputMethodId); + boolean systemIme = isSystemIme(property); + // TODO: Append subtypes by using the separator ";" + if (((N == 1 || systemIme) && !mHaveHardKeyboard) + || (pref != null && pref.isChecked())) { + if (builder.length() > 0) builder.append(':'); + builder.append(id); + if (firstEnabled < 0) { + firstEnabled = i; + } + } else if (currentInputMethod) { + mLastInputMethodId = mLastTickedInputMethodId; + } + // If it's a disabled system ime, add it to the disabled list so that it + // doesn't get enabled automatically on any changes to the package list + if (pref != null && !pref.isChecked() && systemIme && mHaveHardKeyboard) { + if (disabledSysImes.length() > 0) disabledSysImes.append(":"); + disabledSysImes.append(id); + } + } + + // If the last input method is unset, set it as the first enabled one. + if (TextUtils.isEmpty(mLastInputMethodId)) { + if (firstEnabled >= 0) { + mLastInputMethodId = mInputMethodProperties.get(firstEnabled).getId(); + } else { + mLastInputMethodId = null; + } + } + + Settings.Secure.putString(getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS, builder.toString()); + Settings.Secure.putString(getContentResolver(), + Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, disabledSysImes.toString()); + Settings.Secure.putString(getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, + mLastInputMethodId != null ? mLastInputMethodId : ""); + } + + private void setSubtypesPreferenceEnabled(String id, boolean enabled) { + PreferenceScreen preferenceScreen = getPreferenceScreen(); + final int N = mInputMethodProperties.size(); + // TODO: Use iterator. + for (int i = 0; i < N; i++) { + InputMethodInfo imi = mInputMethodProperties.get(i); + if (id.equals(imi.getId())) { + for (InputMethodSubtype subtype: imi.getSubtypes()) { + preferenceScreen.findPreference(id + subtype.hashCode()).setEnabled(enabled); + } + } + } + } + + private boolean isSystemIme(InputMethodInfo property) { + return (property.getServiceInfo().applicationInfo.flags + & ApplicationInfo.FLAG_SYSTEM) != 0; + } +}