From 976bb3f45915bdd5165d9a50402d4c1163dae809 Mon Sep 17 00:00:00 2001 From: Abodunrinwa Toki Date: Wed, 20 Jan 2016 18:43:20 +0000 Subject: [PATCH] Change Input Settings UI flow. 1. Introduces new UI components as per the new flow 2. Temporarily disables components in the old flow that are to be replaced by the new flow. This is done so we can neatly revert to the old flow if there are issues with the new flow 3. AvailableVirtualKeyboardActivity now responds to android.settings.INPUT_METHOD_SETTINGS intents instead of InputMethodAndLanguageSettingsActivity Bug: 25752812 Change-Id: I728d7ee185827ed328c16cb7abce244557a26518 --- AndroidManifest.xml | 22 +- res/values/strings.xml | 19 ++ res/xml/language_settings.xml | 39 ++- res/xml/physical_keyboard_settings.xml | 35 +++ res/xml/virtual_keyboard_settings.xml | 23 ++ .../settings/InstrumentedFragment.java | 3 + src/com/android/settings/Settings.java | 1 + .../android/settings/SettingsActivity.java | 2 + .../AvailableVirtualKeyboardFragment.java | 116 ++++++++ .../InputMethodAndLanguageSettings.java | 18 +- .../KeyboardLayoutDialogFragment.java | 2 +- .../inputmethod/PhysicalKeyboardFragment.java | 264 ++++++++++++++++++ .../inputmethod/VirtualKeyboardFragment.java | 107 +++++++ 13 files changed, 625 insertions(+), 26 deletions(-) create mode 100644 res/xml/physical_keyboard_settings.xml create mode 100644 res/xml/virtual_keyboard_settings.xml create mode 100644 src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java create mode 100644 src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java create mode 100644 src/com/android/settings/inputmethod/VirtualKeyboardFragment.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index eff03972acd..4366b0b876c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -573,14 +573,10 @@ - - - - + android:label="@string/language_keyboard_settings_title" + android:icon="@drawable/ic_settings_language" + android:taskAffinity="com.android.settings" + android:parentActivityName="Settings"> @@ -597,6 +593,16 @@ android:value="true" /> + + + + + + + + Failed to open settings for %1$s + + Keyboard and input methods + + Virtual keyboard + + Physical keyboard + + Available virtual keyboard + + Add a virtual keyboard + + Keyboard assistance + + Show virtual keyboard + + Keep it on screen while physical keyboard is active + + Keyboard shortcuts helper + Mouse/trackpad diff --git a/res/xml/language_settings.xml b/res/xml/language_settings.xml index 83a0985bc90..9cc01456b1d 100644 --- a/res/xml/language_settings.xml +++ b/res/xml/language_settings.xml @@ -41,23 +41,34 @@ /> - + android:title="@string/keyboard_and_input_methods_category"> - + android:title="@string/virtual_keyboard_category" + android:fragment="com.android.settings.inputmethod.VirtualKeyboardFragment" /> + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/virtual_keyboard_settings.xml b/res/xml/virtual_keyboard_settings.xml new file mode 100644 index 00000000000..e5a5f388e09 --- /dev/null +++ b/res/xml/virtual_keyboard_settings.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java index bb2f948105f..ea39cf3e8d7 100644 --- a/src/com/android/settings/InstrumentedFragment.java +++ b/src/com/android/settings/InstrumentedFragment.java @@ -38,6 +38,9 @@ public abstract class InstrumentedFragment extends PreferenceFragment { public static final int BILLING_CYCLE = UNDECLARED + 8; public static final int APP_DATA_USAGE = UNDECLARED + 9; public static final int USER_LOCALE_LIST = UNDECLARED + 10; + public static final int VIRTUAL_KEYBOARDS = UNDECLARED + 11; + public static final int PHYSICAL_KEYBOARDS = UNDECLARED + 12; + public static final int ENABLE_VIRTUAL_KEYBOARDS = UNDECLARED + 13; /** * Declare the view of this category. diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index edd0b4ccd2a..1c636b8d807 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -39,6 +39,7 @@ public class Settings extends SettingsActivity { public static class WifiSettingsActivity extends SettingsActivity { /* empty */ } public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ } public static class InputMethodAndLanguageSettingsActivity extends SettingsActivity { /* empty */ } + public static class AvailableVirtualKeyboardActivity extends SettingsActivity { /* empty */ } public static class KeyboardLayoutPickerActivity extends SettingsActivity { /* empty */ } public static class InputMethodAndSubtypeEnablerActivity extends SettingsActivity { /* empty */ } public static class SpellCheckersSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 403e760fa48..dc134ff4a32 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -77,6 +77,7 @@ import com.android.settings.deviceinfo.StorageSettings; import com.android.settings.fuelgauge.BatterySaverSettings; import com.android.settings.fuelgauge.PowerUsageDetail; import com.android.settings.fuelgauge.PowerUsageSummary; +import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment; import com.android.settings.inputmethod.InputMethodAndLanguageSettings; import com.android.settings.inputmethod.KeyboardLayoutPickerFragment; import com.android.settings.inputmethod.SpellCheckersSettings; @@ -250,6 +251,7 @@ public class SettingsActivity extends SettingsDrawerActivity DateTimeSettings.class.getName(), LocaleListEditor.class.getName(), InputMethodAndLanguageSettings.class.getName(), + AvailableVirtualKeyboardFragment.class.getName(), SpellCheckersSettings.class.getName(), UserDictionaryList.class.getName(), UserDictionarySettings.class.getName(), diff --git a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java new file mode 100644 index 00000000000..2e4242aec65 --- /dev/null +++ b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2016 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 android.app.Activity; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.v7.preference.PreferenceScreen; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; + +import com.android.settings.R; +import com.android.settings.InstrumentedFragment; +import com.android.settings.SettingsPreferenceFragment; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public final class AvailableVirtualKeyboardFragment extends SettingsPreferenceFragment + implements InputMethodPreference.OnSavePreferenceListener { + + private final ArrayList mInputMethodPreferenceList = new ArrayList<>(); + private InputMethodSettingValuesWrapper mInputMethodSettingValues; + private InputMethodManager mImm; + private DevicePolicyManager mDpm; + + @Override + public void onCreatePreferences(Bundle bundle, String s) { + Activity activity = getActivity(); + PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(activity); + screen.setTitle(activity.getString(R.string.available_virtual_keyboard_category)); + setPreferenceScreen(screen); + mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(activity); + mImm = activity.getSystemService(InputMethodManager.class); + mDpm = activity.getSystemService(DevicePolicyManager.class); + } + + @Override + public void onResume() { + super.onResume(); + // Refresh internal states in mInputMethodSettingValues to keep the latest + // "InputMethodInfo"s and "InputMethodSubtype"s + mInputMethodSettingValues.refreshAllInputMethodAndSubtypes(); + updateInputMethodPreferenceViews(); + } + + @Override + public void onSaveInputMethodPreference(final InputMethodPreference pref) { + final boolean hasHardwareKeyboard = getResources().getConfiguration().keyboard + == Configuration.KEYBOARD_QWERTY; + InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(this, getContentResolver(), + mImm.getInputMethodList(), hasHardwareKeyboard); + // Update input method settings and preference list. + mInputMethodSettingValues.refreshAllInputMethodAndSubtypes(); + for (final InputMethodPreference p : mInputMethodPreferenceList) { + p.updatePreferenceViews(); + } + } + + @Override + protected int getMetricsCategory() { + return InstrumentedFragment.ENABLE_VIRTUAL_KEYBOARDS; + } + + private void updateInputMethodPreferenceViews() { + mInputMethodSettingValues.refreshAllInputMethodAndSubtypes(); + // Clear existing "InputMethodPreference"s + mInputMethodPreferenceList.clear(); + List permittedList = mDpm.getPermittedInputMethodsForCurrentUser(); + final Context context = getPrefContext(); + final List imis = mInputMethodSettingValues.getInputMethodList(); + final int N = (imis == null ? 0 : imis.size()); + for (int i = 0; i < N; ++i) { + final InputMethodInfo imi = imis.get(i); + final boolean isAllowedByOrganization = permittedList == null + || permittedList.contains(imi.getPackageName()); + final InputMethodPreference pref = new InputMethodPreference( + context, imi, true, isAllowedByOrganization, this); + mInputMethodPreferenceList.add(pref); + } + final Collator collator = Collator.getInstance(); + Collections.sort(mInputMethodPreferenceList, new Comparator() { + @Override + public int compare(InputMethodPreference lhs, InputMethodPreference rhs) { + return lhs.compareTo(rhs, collator); + } + }); + getPreferenceScreen().removeAll(); + for (int i = 0; i < N; ++i) { + final InputMethodPreference pref = mInputMethodPreferenceList.get(i); + pref.setOrder(i); + getPreferenceScreen().addPreference(pref); + InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref); + pref.updatePreferenceViews(); + } + } +} diff --git a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java index 9022538c094..7564cc75259 100644 --- a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java +++ b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java @@ -157,12 +157,16 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment startingIntent.getAction()); if (mShowsOnlyFullImeAndKeyboardList) { getPreferenceScreen().removeAll(); - getPreferenceScreen().addPreference(mHardKeyboardCategory); + if (mHardKeyboardCategory != null) { + getPreferenceScreen().addPreference(mHardKeyboardCategory); + } if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { getPreferenceScreen().addPreference(mShowInputMethodSelectorPref); } - mKeyboardSettingsCategory.removeAll(); - getPreferenceScreen().addPreference(mKeyboardSettingsCategory); + if (mKeyboardSettingsCategory != null) { + mKeyboardSettingsCategory.removeAll(); + getPreferenceScreen().addPreference(mKeyboardSettingsCategory); + } } // Build hard keyboard and game controller preference categories. @@ -376,6 +380,10 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment } private void updateInputMethodPreferenceViews() { + if (mKeyboardSettingsCategory == null) { + return; + } + synchronized (mInputMethodPreferenceList) { // Clear existing "InputMethodPreference"s for (final InputMethodPreference pref : mInputMethodPreferenceList) { @@ -510,6 +518,10 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment } private void updateHardKeyboards() { + if (mHardKeyboardCategory == null) { + return; + } + mHardKeyboardPreferenceList.clear(); final int[] devices = InputDevice.getDeviceIds(); for (int i = 0; i < devices.length; i++) { diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java b/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java index ad7a2b167a5..68ceeefc062 100644 --- a/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java +++ b/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java @@ -301,7 +301,7 @@ public class KeyboardLayoutDialogFragment extends DialogFragment } } - private static final class KeyboardLayoutLoader extends AsyncTaskLoader { + static final class KeyboardLayoutLoader extends AsyncTaskLoader { private final InputDeviceIdentifier mInputDeviceIdentifier; public KeyboardLayoutLoader(Context context, InputDeviceIdentifier inputDeviceIdentifier) { diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java new file mode 100644 index 00000000000..8f7d99e2595 --- /dev/null +++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2016 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 android.app.Activity; +import android.app.LoaderManager; +import android.content.Intent; +import android.content.Loader; +import android.database.ContentObserver; +import android.hardware.input.InputDeviceIdentifier; +import android.hardware.input.InputManager; +import android.hardware.input.KeyboardLayout; +import android.os.Bundle; +import android.os.Handler; +import android.provider.Settings.Secure; +import android.support.v7.preference.Preference; +import android.support.v7.preference.Preference.OnPreferenceChangeListener; +import android.support.v7.preference.PreferenceCategory; +import android.support.v14.preference.SwitchPreference; +import android.util.Pair; +import android.view.InputDevice; +import android.view.inputmethod.InputMethodInfo; +import android.widget.Toast; + +import com.android.internal.inputmethod.InputMethodUtils; +import com.android.internal.util.Preconditions; +import com.android.settings.R; +import com.android.settings.InstrumentedFragment; +import com.android.settings.Settings; +import com.android.settings.SettingsPreferenceFragment; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment + implements LoaderManager.LoaderCallbacks, + InputManager.InputDeviceListener { + + private static final int USER_SYSTEM = 0; + private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category"; + private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch"; + private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper"; + + private final ArrayList mHardKeyboardPreferenceList = new ArrayList<>(); + private final HashMap> mLoaderReference + = new HashMap<>(); + private InputManager mIm; + private PreferenceCategory mKeyboardAssistanceCategory; + private SwitchPreference mShowVirtualKeyboardSwitch; + private InputMethodUtils.InputMethodSettings mSettings; + + @Override + public void onCreatePreferences(Bundle bundle, String s) { + Activity activity = Preconditions.checkNotNull(getActivity()); + addPreferencesFromResource(R.xml.physical_keyboard_settings); + mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class)); + mSettings = new InputMethodUtils.InputMethodSettings( + activity.getResources(), + getContentResolver(), + new HashMap(), + new ArrayList(), + USER_SYSTEM); + mKeyboardAssistanceCategory = Preconditions.checkNotNull( + (PreferenceCategory) findPreference(KEYBOARD_ASSISTANCE_CATEGORY)); + mShowVirtualKeyboardSwitch = Preconditions.checkNotNull( + (SwitchPreference) mKeyboardAssistanceCategory.findPreference( + SHOW_VIRTUAL_KEYBOARD_SWITCH)); + findPreference(KEYBOARD_SHORTCUTS_HELPER).setOnPreferenceClickListener( + new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + toggleKeyboardShortcutsMenu(); + return true; + } + }); + } + + @Override + public void onResume() { + super.onResume(); + updateHardKeyboards(); + mIm.registerInputDeviceListener(this, null); + mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener( + mShowVirtualKeyboardSwitchPreferenceChangeListener); + registerShowVirtualKeyboardSettingsObserver(); + } + + @Override + public void onPause() { + super.onPause(); + clearHardKeyboardsData(); + mIm.unregisterInputDeviceListener(this); + mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(null); + unregisterShowVirtualKeyboardSettingsObserver(); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + InputDeviceIdentifier deviceId = mLoaderReference.get(id).first; + return new KeyboardLayoutDialogFragment.KeyboardLayoutLoader( + getActivity().getBaseContext(), deviceId); + } + + @Override + public void onLoadFinished( + final Loader loader, + KeyboardLayoutDialogFragment.Keyboards data) { + // TODO: Investigate why this is being called twice. + final InputDeviceIdentifier deviceId = mLoaderReference.get(loader.getId()).first; + final PreferenceCategory category = mLoaderReference.get(loader.getId()).second; + category.removeAll(); + for (KeyboardLayout layout : data.keyboardLayouts) { + if (layout != null) { + Preference pref = new Preference(getPrefContext(), null); + pref.setTitle(layout.getLabel()); + pref.setSummary(layout.getCollection()); + pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + showKeyboardLayoutScreen(deviceId); + return true; + } + }); + category.addPreference(pref); + } + } + } + + @Override + public void onLoaderReset(Loader loader) {} + + @Override + public void onInputDeviceAdded(int deviceId) { + updateHardKeyboards(); + } + + @Override + public void onInputDeviceRemoved(int deviceId) { + updateHardKeyboards(); + } + + @Override + public void onInputDeviceChanged(int deviceId) { + updateHardKeyboards(); + } + + @Override + protected int getMetricsCategory() { + return InstrumentedFragment.PHYSICAL_KEYBOARDS; + } + + private void updateHardKeyboards() { + clearHardKeyboardsData(); + final int[] devices = InputDevice.getDeviceIds(); + for (int deviceIndex = 0; deviceIndex < devices.length; deviceIndex++) { + InputDevice device = InputDevice.getDevice(devices[deviceIndex]); + if (device != null + && !device.isVirtual() + && device.isFullKeyboard()) { + final InputDeviceIdentifier deviceId = device.getIdentifier(); + final String keyboardLayoutDescriptor = + mIm.getCurrentKeyboardLayoutForInputDevice(deviceId); + final KeyboardLayout keyboardLayout = keyboardLayoutDescriptor != null ? + mIm.getKeyboardLayout(keyboardLayoutDescriptor) : null; + + final PreferenceCategory category = new PreferenceCategory(getPrefContext(), null); + category.setTitle(device.getName()); + if (keyboardLayout != null) { + category.setSummary(keyboardLayout.toString()); + } else { + category.setSummary(R.string.keyboard_layout_default_label); + } + mLoaderReference.put(deviceIndex, new Pair(deviceId, category)); + mHardKeyboardPreferenceList.add(category); + } + } + + Collections.sort(mHardKeyboardPreferenceList); + final int count = mHardKeyboardPreferenceList.size(); + for (int i = 0; i < count; i++) { + final PreferenceCategory category = mHardKeyboardPreferenceList.get(i); + category.setOrder(i); + getPreferenceScreen().addPreference(category); + } + mKeyboardAssistanceCategory.setOrder(count); + getPreferenceScreen().addPreference(mKeyboardAssistanceCategory); + + for (int deviceIndex : mLoaderReference.keySet()) { + getLoaderManager().initLoader(deviceIndex, null, this); + } + updateShowVirtualKeyboardSwitch(); + } + + private void showKeyboardLayoutScreen(InputDeviceIdentifier inputDeviceIdentifier) { + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class); + intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER, + inputDeviceIdentifier); + startActivity(intent); + } + + private void clearHardKeyboardsData() { + getPreferenceScreen().removeAll(); + for (int index = 0; index < mLoaderReference.size(); index++) { + getLoaderManager().destroyLoader(index); + } + mLoaderReference.clear(); + mHardKeyboardPreferenceList.clear(); + } + + private void registerShowVirtualKeyboardSettingsObserver() { + unregisterShowVirtualKeyboardSettingsObserver(); + getActivity().getContentResolver().registerContentObserver( + Secure.getUriFor(Secure.SHOW_IME_WITH_HARD_KEYBOARD), + false, + mContentObserver, + USER_SYSTEM); + updateShowVirtualKeyboardSwitch(); + } + + private void unregisterShowVirtualKeyboardSettingsObserver() { + getActivity().getContentResolver().unregisterContentObserver(mContentObserver); + } + + private void updateShowVirtualKeyboardSwitch() { + mShowVirtualKeyboardSwitch.setChecked(mSettings.isShowImeWithHardKeyboardEnabled()); + } + + private void toggleKeyboardShortcutsMenu() { + // TODO: Implement. + Toast.makeText(getActivity(), "toggleKeyboardShortcutsMenu", Toast.LENGTH_SHORT).show(); + } + + private final OnPreferenceChangeListener mShowVirtualKeyboardSwitchPreferenceChangeListener = + new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mSettings.setShowImeWithHardKeyboard((Boolean) newValue); + return false; + } + }; + + private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) { + @Override + public void onChange(boolean selfChange) { + updateShowVirtualKeyboardSwitch(); + } + }; +} diff --git a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java new file mode 100644 index 00000000000..541c68655e9 --- /dev/null +++ b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2016 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 android.app.Activity; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.Bundle; +import android.support.v7.preference.Preference; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; + +import com.android.internal.util.Preconditions; +import com.android.settings.R; +import com.android.settings.InstrumentedFragment; +import com.android.settings.SettingsPreferenceFragment; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public final class VirtualKeyboardFragment extends SettingsPreferenceFragment { + + private static final String ADD_VIRTUAL_KEYBOARD_SCREEN = "add_virtual_keyboard_screen"; + + private final ArrayList mInputMethodPreferenceList = new ArrayList<>(); + private InputMethodManager mImm; + private DevicePolicyManager mDpm; + private Preference mAddVirtualKeyboardScreen; + + @Override + public void onCreatePreferences(Bundle bundle, String s) { + Activity activity = Preconditions.checkNotNull(getActivity()); + addPreferencesFromResource(R.xml.virtual_keyboard_settings); + mImm = Preconditions.checkNotNull(activity.getSystemService(InputMethodManager.class)); + mDpm = Preconditions.checkNotNull(activity.getSystemService(DevicePolicyManager.class)); + mAddVirtualKeyboardScreen = Preconditions.checkNotNull( + findPreference(ADD_VIRTUAL_KEYBOARD_SCREEN)); + } + + @Override + public void onResume() { + super.onResume(); + // Refresh internal states in mInputMethodSettingValues to keep the latest + // "InputMethodInfo"s and "InputMethodSubtype"s + updateInputMethodPreferenceViews(); + } + + @Override + protected int getMetricsCategory() { + return InstrumentedFragment.VIRTUAL_KEYBOARDS; + } + + private void updateInputMethodPreferenceViews() { + // Clear existing "InputMethodPreference"s + mInputMethodPreferenceList.clear(); + List permittedList = mDpm.getPermittedInputMethodsForCurrentUser(); + final Context context = getPrefContext(); + final List imis = mImm.getEnabledInputMethodList(); + final int N = (imis == null ? 0 : imis.size()); + for (int i = 0; i < N; ++i) { + final InputMethodInfo imi = imis.get(i); + final boolean isAllowedByOrganization = permittedList == null + || permittedList.contains(imi.getPackageName()); + final InputMethodPreference pref = new InputMethodPreference( + context, + imi, + false, /* isImeEnabler */ + isAllowedByOrganization, + null /* this can be null since isImeEnabler is false */); + mInputMethodPreferenceList.add(pref); + } + final Collator collator = Collator.getInstance(); + Collections.sort(mInputMethodPreferenceList, new Comparator() { + @Override + public int compare(InputMethodPreference lhs, InputMethodPreference rhs) { + return lhs.compareTo(rhs, collator); + } + }); + getPreferenceScreen().removeAll(); + for (int i = 0; i < N; ++i) { + final InputMethodPreference pref = mInputMethodPreferenceList.get(i); + pref.setOrder(i); + getPreferenceScreen().addPreference(pref); + InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref); + pref.updatePreferenceViews(); + } + mAddVirtualKeyboardScreen.setOrder(N); + getPreferenceScreen().addPreference(mAddVirtualKeyboardScreen); + } +}