diff --git a/AndroidManifest.xml b/AndroidManifest.xml index fea3b01f2f7..8a54d3efbe5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -396,6 +396,19 @@ android:resource="@id/language_settings" /> + + + + + + + + + Pointer speed + + + Choose keyboard layout + + No keyboard layouts are available. + User dictionary diff --git a/res/xml/language_settings.xml b/res/xml/language_settings.xml index fbfb3d7aa1e..cfcc34135df 100644 --- a/res/xml/language_settings.xml +++ b/res/xml/language_settings.xml @@ -36,27 +36,34 @@ + + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 3513dcc339e..9d000244689 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -609,6 +609,7 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { public static class WifiSettingsActivity extends Settings { /* empty */ } public static class WifiP2pSettingsActivity extends Settings { /* empty */ } public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ } + public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ } public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ } public static class SpellCheckersSettingsActivity extends Settings { /* empty */ } public static class LocalePickerActivity extends Settings { /* empty */ } diff --git a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java index 44543898b5b..cc2cf0abdc9 100644 --- a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java +++ b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java @@ -17,6 +17,7 @@ package com.android.settings.inputmethod; import com.android.settings.R; +import com.android.settings.Settings.KeyboardLayoutPickerActivity; import com.android.settings.Settings.SpellCheckersSettingsActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; @@ -29,6 +30,8 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.ContentObserver; +import android.hardware.input.InputManager; +import android.hardware.input.InputManager.KeyboardLayout; import android.os.Bundle; import android.os.Handler; import android.preference.CheckBoxPreference; @@ -40,11 +43,15 @@ import android.preference.PreferenceScreen; import android.provider.Settings; import android.provider.Settings.System; import android.text.TextUtils; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyCharacterMap.UnavailableException; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Set; @@ -68,11 +75,13 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment private int mDefaultInputMethodSelectorVisibility = 0; private ListPreference mShowInputMethodSelectorPref; - private Preference mLanguagePref; - private ArrayList mInputMethodPreferenceList = - new ArrayList(); - private boolean mHaveHardKeyboard; + private PreferenceCategory mKeyboardSettingsCategory; private PreferenceCategory mHardKeyboardCategory; + private Preference mLanguagePref; + private final ArrayList mInputMethodPreferenceList = + new ArrayList(); + private final ArrayList mHardKeyboardPreferenceList = + new ArrayList(); private InputMethodManager mImm; private List mImis; private boolean mIsOnlyImeSettings; @@ -108,18 +117,55 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment new VoiceInputOutputSettings(this).onCreate(); - // Hard keyboard - final Configuration config = getResources().getConfiguration(); - mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY); + // Get references to dynamically constructed categories. + mHardKeyboardCategory = (PreferenceCategory)findPreference("hard_keyboard"); + mKeyboardSettingsCategory = (PreferenceCategory)findPreference( + "keyboard_settings_category"); - // IME + // Filter out irrelevant features if invoked from IME settings button. mIsOnlyImeSettings = Settings.ACTION_INPUT_METHOD_SETTINGS.equals( getActivity().getIntent().getAction()); getActivity().getIntent().setAction(null); + if (mIsOnlyImeSettings) { + getPreferenceScreen().removeAll(); + getPreferenceScreen().addPreference(mHardKeyboardCategory); + if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { + getPreferenceScreen().addPreference(mShowInputMethodSelectorPref); + } + getPreferenceScreen().addPreference(mKeyboardSettingsCategory); + } + + // Build IME preference category. mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); mImis = mImm.getInputMethodList(); - createImePreferenceHierarchy((PreferenceGroup)findPreference("keyboard_settings_category")); + mKeyboardSettingsCategory.removeAll(); + if (!mIsOnlyImeSettings) { + final PreferenceScreen currentIme = new PreferenceScreen(getActivity(), null); + currentIme.setKey(KEY_CURRENT_INPUT_METHOD); + currentIme.setTitle(getResources().getString(R.string.current_input_method)); + mKeyboardSettingsCategory.addPreference(currentIme); + } + + mInputMethodPreferenceList.clear(); + final int N = (mImis == null ? 0 : mImis.size()); + for (int i = 0; i < N; ++i) { + final InputMethodInfo imi = mImis.get(i); + final InputMethodPreference pref = getInputMethodPreference(imi, N); + mInputMethodPreferenceList.add(pref); + } + + if (!mInputMethodPreferenceList.isEmpty()) { + Collections.sort(mInputMethodPreferenceList); + for (int i = 0; i < N; ++i) { + mKeyboardSettingsCategory.addPreference(mInputMethodPreferenceList.get(i)); + } + } + + // Build hard keyboard preference category. + updateHardKeyboards(); + + // Spell Checker final Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClass(getActivity(), SpellCheckersSettingsActivity.class); final SpellCheckersPreference scp = ((SpellCheckersPreference)findPreference( @@ -189,7 +235,7 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment } // Hard keyboard - if (mHaveHardKeyboard) { + if (!mHardKeyboardPreferenceList.isEmpty()) { for (int i = 0; i < sHardKeyboardKeys.length; ++i) { CheckBoxPreference chkPref = (CheckBoxPreference) mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i]); @@ -198,6 +244,8 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment } } + updateHardKeyboards(); + // IME InputMethodAndSubtypeUtil.loadInputMethodSubtypeList( this, getContentResolver(), mImis, null); @@ -211,7 +259,7 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment mShowInputMethodSelectorPref.setOnPreferenceChangeListener(null); } InputMethodAndSubtypeUtil.saveInputMethodSubtypeList( - this, getContentResolver(), mImis, mHaveHardKeyboard); + this, getContentResolver(), mImis, !mHardKeyboardPreferenceList.isEmpty()); } @Override @@ -230,7 +278,7 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment } } else if (preference instanceof CheckBoxPreference) { final CheckBoxPreference chkPref = (CheckBoxPreference) preference; - if (mHaveHardKeyboard) { + if (!mHardKeyboardPreferenceList.isEmpty()) { for (int i = 0; i < sHardKeyboardKeys.length; ++i) { if (chkPref == mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i])) { System.putInt(getContentResolver(), sSystemSettingNames[i], @@ -315,46 +363,57 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment return pref; } - private void createImePreferenceHierarchy(PreferenceGroup root) { - final Preference hardKeyPref = findPreference("hard_keyboard"); - if (mIsOnlyImeSettings) { - getPreferenceScreen().removeAll(); - if (hardKeyPref != null && mHaveHardKeyboard) { - getPreferenceScreen().addPreference(hardKeyPref); - } - if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { - getPreferenceScreen().addPreference(mShowInputMethodSelectorPref); - } - getPreferenceScreen().addPreference(root); - } - if (hardKeyPref != null) { - if (mHaveHardKeyboard) { - mHardKeyboardCategory = (PreferenceCategory) hardKeyPref; - } else { - getPreferenceScreen().removePreference(hardKeyPref); + private void updateHardKeyboards() { + mHardKeyboardPreferenceList.clear(); + if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY) { + final InputManager im = + (InputManager)getActivity().getSystemService(Context.INPUT_SERVICE); + + final int[] devices = InputDevice.getDeviceIds(); + for (int i = 0; i < devices.length; i++) { + InputDevice device = InputDevice.getDevice(devices[i]); + if (device != null + && (device.getSources() & InputDevice.SOURCE_KEYBOARD) != 0 + && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) { + final String inputDeviceDescriptor = device.getDescriptor(); + final String keyboardLayoutDescriptor = + im.getInputDeviceKeyboardLayoutDescriptor(inputDeviceDescriptor); + final KeyboardLayout keyboardLayout = keyboardLayoutDescriptor != null ? + im.getKeyboardLayout(keyboardLayoutDescriptor) : null; + + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClass(getActivity(), KeyboardLayoutPickerActivity.class); + intent.putExtra(KeyboardLayoutPicker.EXTRA_INPUT_DEVICE_DESCRIPTOR, + inputDeviceDescriptor); + + final PreferenceScreen pref = new PreferenceScreen(getActivity(), null); + pref.setTitle(device.getName()); + if (keyboardLayout != null) { + pref.setSummary(keyboardLayout.getLabel()); + } + pref.setIntent(intent); + mHardKeyboardPreferenceList.add(pref); + } } } - root.removeAll(); - mInputMethodPreferenceList.clear(); - if (!mIsOnlyImeSettings) { - // Current IME selection - final PreferenceScreen currentIme = new PreferenceScreen(getActivity(), null); - currentIme.setKey(KEY_CURRENT_INPUT_METHOD); - currentIme.setTitle(getResources().getString(R.string.current_input_method)); - root.addPreference(currentIme); - } + if (!mHardKeyboardPreferenceList.isEmpty()) { + for (int i = mHardKeyboardCategory.getPreferenceCount(); i-- > 0; ) { + final Preference pref = mHardKeyboardCategory.getPreference(i); + if (pref.getOrder() < 1000) { + mHardKeyboardCategory.removePreference(pref); + } + } - final int N = (mImis == null ? 0 : mImis.size()); - for (int i = 0; i < N; ++i) { - final InputMethodInfo imi = mImis.get(i); - final InputMethodPreference pref = getInputMethodPreference(imi, N); - mInputMethodPreferenceList.add(pref); - } - - Collections.sort(mInputMethodPreferenceList); - for (int i = 0; i < N; ++i) { - root.addPreference(mInputMethodPreferenceList.get(i)); + Collections.sort(mHardKeyboardPreferenceList); + final int count = mHardKeyboardPreferenceList.size(); + for (int i = 0; i < count; i++) { + final Preference pref = mHardKeyboardPreferenceList.get(i); + pref.setOrder(i); + mHardKeyboardCategory.addPreference(pref); + } + } else { + getPreferenceScreen().removePreference(mHardKeyboardCategory); } } diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPicker.java b/src/com/android/settings/inputmethod/KeyboardLayoutPicker.java new file mode 100644 index 00000000000..472df3abc13 --- /dev/null +++ b/src/com/android/settings/inputmethod/KeyboardLayoutPicker.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2012 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.inputmethod; + +import com.android.settings.R; + +import android.app.ListFragment; +import android.app.LoaderManager.LoaderCallbacks; +import android.content.AsyncTaskLoader; +import android.content.Context; +import android.content.Loader; +import android.hardware.input.InputManager; +import android.hardware.input.InputManager.KeyboardLayout; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; +import android.widget.ListView; + +import java.util.Collections; +import java.util.List; + +public class KeyboardLayoutPicker extends ListFragment + implements LoaderCallbacks> { + private static final String TAG = "KeyboardLayoutPicker"; + + private String mInputDeviceDescriptor; + + /** + * Intent extra: The input device descriptor of the keyboard whose keyboard + * layout is to be changed. + */ + public static final String EXTRA_INPUT_DEVICE_DESCRIPTOR = "input_device_descriptor"; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mInputDeviceDescriptor = getActivity().getIntent().getStringExtra( + EXTRA_INPUT_DEVICE_DESCRIPTOR); + if (mInputDeviceDescriptor == null) { + Log.e(TAG, "Missing expected intent parameter: " + EXTRA_INPUT_DEVICE_DESCRIPTOR); + getActivity().finish(); + } + + setEmptyText(getActivity().getText(R.string.keyboard_layout_picker_empty_text)); + getLoaderManager().initLoader(0, null, this); + } + + @Override + public void onResume() { + super.onResume(); + getListView().requestFocus(); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + if (mInputDeviceDescriptor != null) { + KeyboardLayout c = (KeyboardLayout)l.getItemAtPosition(position); + InputManager im = (InputManager)getActivity().getSystemService(Context.INPUT_SERVICE); + im.setInputDeviceKeyboardLayoutDescriptor(mInputDeviceDescriptor, c.getDescriptor()); + } + + getActivity().finish(); + } + + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return new KeyboardLayoutLoader(getActivity()); + } + + @Override + public void onLoadFinished(Loader> loader, + List data) { + setListAdapter(new KeyboardLayoutAdapter(getActivity(), data)); + } + + @Override + public void onLoaderReset(Loader> loader) { + setListAdapter(null); + } + + private static final class KeyboardLayoutAdapter + extends ArrayAdapter { + public KeyboardLayoutAdapter(Context context, List list) { + super(context, android.R.layout.simple_list_item_1, list); + } + } + + private static final class KeyboardLayoutLoader + extends AsyncTaskLoader> { + public KeyboardLayoutLoader(Context context) { + super(context); + } + + @Override + public List loadInBackground() { + InputManager im = (InputManager)getContext().getSystemService(Context.INPUT_SERVICE); + List list = im.getKeyboardLayouts(); + Collections.sort(list); + return list; + } + + @Override + protected void onStartLoading() { + super.onStartLoading(); + forceLoad(); + } + + @Override + protected void onStopLoading() { + super.onStopLoading(); + cancelLoad(); + } + } +}