Add UI to select multiple keyboard layouts.

Bug: 6405203
Change-Id: I27ca4630aebcb39b83298d37d8fb3f4ef0080317
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3cf1520..8386c3a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -433,7 +433,7 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                android:value="com.android.settings.inputmethod.KeyboardLayoutPicker" />
+                android:value="com.android.settings.inputmethod.KeyboardLayoutPickerFragment" />
             <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
                 android:resource="@id/language_settings" />
         </activity>
diff --git a/res/layout/keyboard_layout_dialog_switch_hint.xml b/res/layout/keyboard_layout_dialog_switch_hint.xml
new file mode 100644
index 0000000..336d543
--- /dev/null
+++ b/res/layout/keyboard_layout_dialog_switch_hint.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <ImageView android:id="@+id/titleDivider"
+        android:layout_width="match_parent"
+        android:layout_height="1dip"
+        android:scaleType="fitXY"
+        android:gravity="fill_horizontal"
+        android:src="@android:drawable/divider_horizontal_dark" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/keyboard_layout_dialog_switch_hint"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="?android:attr/textColorAlertDialogListItem"
+        android:minHeight="48dp"
+        android:gravity="center" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3c46b48..543c659 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2659,14 +2659,20 @@
     <!-- On Language & input settings screen, setting summary.  Setting to redirect vibration to input devices. [CHAR LIMIT=100] -->
     <string name="vibrate_input_devices_summary">Redirect vibrator to game controller when connected.</string>
 
-    <!-- Keyboard Layout Picker --> <skip />
-    <!-- Title for the keyboard layout picker activity. [CHAR LIMIT=35] -->
-    <string name="keyboard_layout_picker_title">Choose keyboard layout</string>
-    <!-- String to show when no keyboard layouts are available. [CHAR LIMIT=60] -->
-    <string name="keyboard_layout_picker_empty_text">No keyboard layouts are available.</string>
+    <!-- Keyboard Layout Preference Dialog --> <skip />
+    <!-- Title for the keyboard layout preference dialog. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_dialog_title">Choose keyboard layout</string>
+    <!-- Button to configure keyboard layouts.  [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_dialog_setup_button">Set up keyboard layouts</string>
+    <!-- Hint describing how to switch keyboard layouts using the keyboard.  [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_dialog_switch_hint">(Switch with ctrl-space)</string>
     <!-- Label of the default keyboard layout.  [CHAR LIMIT=35] -->
     <string name="keyboard_layout_default_label">Default</string>
 
+    <!-- Keyboard Layout Picker --> <skip />
+    <!-- Title for the keyboard layout picker activity. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_picker_title">Keyboard layouts</string>
+
     <!-- User dictionary settings --><skip />
     <!-- User dictionary settings, The titlebar text of the User dictionary settings screen. -->
     <string name="user_dict_settings_titlebar">User dictionary</string>
diff --git a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
index 8c341c6..d848503 100644
--- a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
+++ b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
@@ -52,7 +52,8 @@
 import java.util.TreeSet;
 
 public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
-        implements Preference.OnPreferenceChangeListener, InputManager.InputDeviceListener {
+        implements Preference.OnPreferenceChangeListener, InputManager.InputDeviceListener,
+        KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener {
 
     private static final String KEY_PHONE_LANGUAGE = "phone_language";
     private static final String KEY_CURRENT_INPUT_METHOD = "current_input_method";
@@ -86,6 +87,7 @@
     private Handler mHandler;
     @SuppressWarnings("unused")
     private SettingsObserver mSettingsObserver;
+    private Intent mIntentWaitingForResult;
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -409,15 +411,10 @@
                         && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
                     final String inputDeviceDescriptor = device.getDescriptor();
                     final String keyboardLayoutDescriptor =
-                            mIm.getKeyboardLayoutForInputDevice(inputDeviceDescriptor);
+                            mIm.getCurrentKeyboardLayoutForInputDevice(inputDeviceDescriptor);
                     final KeyboardLayout keyboardLayout = keyboardLayoutDescriptor != null ?
                             mIm.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) {
@@ -425,7 +422,13 @@
                     } else {
                         pref.setSummary(R.string.keyboard_layout_default_label);
                     }
-                    pref.setIntent(intent);
+                    pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+                        @Override
+                        public boolean onPreferenceClick(Preference preference) {
+                            showKeyboardLayoutDialog(inputDeviceDescriptor);
+                            return true;
+                        }
+                    });
                     mHardKeyboardPreferenceList.add(pref);
                 }
             }
@@ -453,6 +456,35 @@
         }
     }
 
+    private void showKeyboardLayoutDialog(String inputDeviceDescriptor) {
+        KeyboardLayoutDialogFragment fragment =
+                new KeyboardLayoutDialogFragment(inputDeviceDescriptor);
+        fragment.setTargetFragment(this, 0);
+        fragment.show(getActivity().getFragmentManager(), "keyboardLayout");
+    }
+
+    @Override
+    public void onSetupKeyboardLayouts(String inputDeviceDescriptor) {
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClass(getActivity(), KeyboardLayoutPickerActivity.class);
+        intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_DESCRIPTOR,
+                inputDeviceDescriptor);
+        mIntentWaitingForResult = intent;
+        startActivityForResult(intent, 0);
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (mIntentWaitingForResult != null) {
+            String inputDeviceDescriptor = mIntentWaitingForResult.getStringExtra(
+                    KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_DESCRIPTOR);
+            mIntentWaitingForResult = null;
+            showKeyboardLayoutDialog(inputDeviceDescriptor);
+        }
+    }
+
     private void updateGameControllers() {
         if (haveInputDeviceWithVibrator()) {
             getPreferenceScreen().addPreference(mGameControllerCategory);
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java b/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java
new file mode 100644
index 0000000..a232a0f
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java
@@ -0,0 +1,354 @@
+/*
+ * 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 com.android.settings.Settings.KeyboardLayoutPickerActivity;
+
+import android.app.AlertDialog;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.Loader;
+import android.content.res.Resources;
+import android.hardware.input.InputManager;
+import android.hardware.input.KeyboardLayout;
+import android.hardware.input.InputManager.InputDeviceListener;
+import android.os.Bundle;
+import android.view.InputDevice;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CheckedTextView;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class KeyboardLayoutDialogFragment extends DialogFragment
+        implements InputDeviceListener, LoaderCallbacks<KeyboardLayoutDialogFragment.Keyboards> {
+    private static final String KEY_INPUT_DEVICE_DESCRIPTOR = "inputDeviceDescriptor";
+
+    private String mInputDeviceDescriptor;
+    private int mInputDeviceId = -1;
+    private InputManager mIm;
+    private KeyboardLayoutAdapter mAdapter;
+
+    public KeyboardLayoutDialogFragment() {
+    }
+
+    public KeyboardLayoutDialogFragment(String inputDeviceDescriptor) {
+        mInputDeviceDescriptor = inputDeviceDescriptor;
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+
+        Context context = activity.getBaseContext();
+        mIm = (InputManager)context.getSystemService(Context.INPUT_SERVICE);
+        mAdapter = new KeyboardLayoutAdapter(context);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState != null) {
+            mInputDeviceDescriptor = savedInstanceState.getString(KEY_INPUT_DEVICE_DESCRIPTOR);
+        }
+
+        getLoaderManager().initLoader(0, null, this);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putString(KEY_INPUT_DEVICE_DESCRIPTOR, mInputDeviceDescriptor);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Context context = getActivity();
+        LayoutInflater inflater = LayoutInflater.from(context);
+        AlertDialog.Builder builder = new AlertDialog.Builder(context)
+            .setTitle(R.string.keyboard_layout_dialog_title)
+            .setPositiveButton(R.string.keyboard_layout_dialog_setup_button,
+                    new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            onSetupLayoutsButtonClicked();
+                        }
+                    })
+            .setSingleChoiceItems(mAdapter, -1,
+                    new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            onKeyboardLayoutClicked(which);
+                        }
+                    })
+            .setView(inflater.inflate(R.layout.keyboard_layout_dialog_switch_hint, null));
+        updateSwitchHintVisibility();
+        return builder.create();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        mIm.registerInputDeviceListener(this, null);
+
+        InputDevice inputDevice = mIm.getInputDeviceByDescriptor(mInputDeviceDescriptor);
+        if (inputDevice == null) {
+            dismiss();
+            return;
+        }
+        mInputDeviceId = inputDevice.getId();
+    }
+
+    @Override
+    public void onPause() {
+        mIm.unregisterInputDeviceListener(this);
+        mInputDeviceId = -1;
+
+        super.onPause();
+    }
+
+    @Override
+    public void onCancel(DialogInterface dialog) {
+        super.onCancel(dialog);
+        dismiss();
+    }
+
+    private void onSetupLayoutsButtonClicked() {
+        ((OnSetupKeyboardLayoutsListener)getTargetFragment()).onSetupKeyboardLayouts(
+                mInputDeviceDescriptor);
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        show(getActivity().getFragmentManager(), "layout");
+    }
+
+    private void onKeyboardLayoutClicked(int which) {
+        if (which >= 0 && which < mAdapter.getCount()) {
+            KeyboardLayout keyboardLayout = mAdapter.getItem(which);
+            if (keyboardLayout != null) {
+                mIm.setCurrentKeyboardLayoutForInputDevice(mInputDeviceDescriptor,
+                        keyboardLayout.getDescriptor());
+            }
+            dismiss();
+        }
+    }
+
+    @Override
+    public Loader<Keyboards> onCreateLoader(int id, Bundle args) {
+        return new KeyboardLayoutLoader(getActivity().getBaseContext(), mInputDeviceDescriptor);
+    }
+
+    @Override
+    public void onLoadFinished(Loader<Keyboards> loader, Keyboards data) {
+        mAdapter.clear();
+        mAdapter.addAll(data.keyboardLayouts);
+        mAdapter.setCheckedItem(data.current);
+        AlertDialog dialog = (AlertDialog)getDialog();
+        if (dialog != null) {
+            dialog.getListView().setItemChecked(data.current, true);
+        }
+        updateSwitchHintVisibility();
+    }
+
+    @Override
+    public void onLoaderReset(Loader<Keyboards> loader) {
+        mAdapter.clear();
+        updateSwitchHintVisibility();
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+            getLoaderManager().restartLoader(0, null, this);
+        }
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+            dismiss();
+        }
+    }
+
+    private void updateSwitchHintVisibility() {
+        AlertDialog dialog = (AlertDialog)getDialog();
+        if (dialog != null) {
+            View customPanel = dialog.findViewById(com.android.internal.R.id.customPanel);
+            customPanel.setVisibility(mAdapter.getCount() > 1 ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    private static final class KeyboardLayoutAdapter extends ArrayAdapter<KeyboardLayout> {
+        private final LayoutInflater mInflater;
+        private int mCheckedItem = -1;
+
+        public KeyboardLayoutAdapter(Context context) {
+            super(context, com.android.internal.R.layout.simple_list_item_2_single_choice);
+            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        }
+
+        public void setCheckedItem(int position) {
+            mCheckedItem = position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            KeyboardLayout item = getItem(position);
+            String label, collection;
+            if (item != null) {
+                label = item.getLabel();
+                collection = item.getCollection();
+            } else {
+                label = getContext().getString(R.string.keyboard_layout_default_label);
+                collection = "";
+            }
+
+            boolean checked = (position == mCheckedItem);
+            if (collection.isEmpty()) {
+                return inflateOneLine(convertView, parent, label, checked);
+            } else {
+                return inflateTwoLine(convertView, parent, label, collection, checked);
+            }
+        }
+
+        private View inflateOneLine(View convertView, ViewGroup parent,
+                String label, boolean checked) {
+            View view = convertView;
+            if (view == null || isTwoLine(view)) {
+                view = mInflater.inflate(
+                        com.android.internal.R.layout.simple_list_item_single_choice,
+                        parent, false);
+                setTwoLine(view, false);
+            }
+            CheckedTextView headline = (CheckedTextView) view.findViewById(android.R.id.text1);
+            headline.setText(label);
+            headline.setChecked(checked);
+            return view;
+        }
+
+        private View inflateTwoLine(View convertView, ViewGroup parent,
+                String label, String collection, boolean checked) {
+            View view = convertView;
+            if (view == null || !isTwoLine(view)) {
+                view = mInflater.inflate(
+                        com.android.internal.R.layout.simple_list_item_2_single_choice,
+                        parent, false);
+                setTwoLine(view, true);
+            }
+            TextView headline = (TextView) view.findViewById(android.R.id.text1);
+            TextView subText = (TextView) view.findViewById(android.R.id.text2);
+            RadioButton radioButton =
+                    (RadioButton)view.findViewById(com.android.internal.R.id.radio);
+            headline.setText(label);
+            subText.setText(collection);
+            radioButton.setChecked(checked);
+            return view;
+        }
+
+        private static boolean isTwoLine(View view) {
+            return view.getTag() == Boolean.TRUE;
+        }
+
+        private static void setTwoLine(View view, boolean twoLine) {
+            view.setTag(Boolean.valueOf(twoLine));
+        }
+    }
+
+    private static final class KeyboardLayoutLoader extends AsyncTaskLoader<Keyboards> {
+        private final String mInputDeviceDescriptor;
+
+        public KeyboardLayoutLoader(Context context, String inputDeviceDescriptor) {
+            super(context);
+            mInputDeviceDescriptor = inputDeviceDescriptor;
+        }
+
+        @Override
+        public Keyboards loadInBackground() {
+            Keyboards keyboards = new Keyboards();
+            InputManager im = (InputManager)getContext().getSystemService(Context.INPUT_SERVICE);
+            String[] keyboardLayoutDescriptors = im.getKeyboardLayoutsForInputDevice(
+                    mInputDeviceDescriptor);
+            for (String keyboardLayoutDescriptor : keyboardLayoutDescriptors) {
+                KeyboardLayout keyboardLayout = im.getKeyboardLayout(keyboardLayoutDescriptor);
+                if (keyboardLayout != null) {
+                    keyboards.keyboardLayouts.add(keyboardLayout);
+                }
+            }
+            Collections.sort(keyboards.keyboardLayouts);
+
+            String currentKeyboardLayoutDescriptor =
+                    im.getCurrentKeyboardLayoutForInputDevice(mInputDeviceDescriptor);
+            if (currentKeyboardLayoutDescriptor != null) {
+                final int numKeyboardLayouts = keyboards.keyboardLayouts.size();
+                for (int i = 0; i < numKeyboardLayouts; i++) {
+                    if (keyboards.keyboardLayouts.get(i).getDescriptor().equals(
+                            currentKeyboardLayoutDescriptor)) {
+                        keyboards.current = i;
+                        break;
+                    }
+                }
+            }
+
+            if (keyboards.keyboardLayouts.isEmpty()) {
+                keyboards.keyboardLayouts.add(null); // default layout
+                keyboards.current = 0;
+            }
+            return keyboards;
+        }
+
+        @Override
+        protected void onStartLoading() {
+            super.onStartLoading();
+            forceLoad();
+        }
+
+        @Override
+        protected void onStopLoading() {
+            super.onStopLoading();
+            cancelLoad();
+        }
+    }
+
+    public static final class Keyboards {
+        public final ArrayList<KeyboardLayout> keyboardLayouts = new ArrayList<KeyboardLayout>();
+        public int current = -1;
+    }
+
+    public interface OnSetupKeyboardLayoutsListener {
+        public void onSetupKeyboardLayouts(String inputDeviceDescriptor);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPicker.java b/src/com/android/settings/inputmethod/KeyboardLayoutPicker.java
deleted file mode 100644
index 6c341b8..0000000
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPicker.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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.KeyboardLayout;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import java.util.Arrays;
-
-public class KeyboardLayoutPicker extends ListFragment
-        implements LoaderCallbacks<KeyboardLayout[]> {
-    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.setKeyboardLayoutForInputDevice(mInputDeviceDescriptor, c.getDescriptor());
-        }
-
-        getActivity().finish();
-    }
-
-    @Override
-    public Loader<KeyboardLayout[]> onCreateLoader(int id, Bundle args) {
-        return new KeyboardLayoutLoader(getActivity());
-    }
-
-    @Override
-    public void onLoadFinished(Loader<KeyboardLayout[]> loader,
-            KeyboardLayout[] data) {
-        setListAdapter(new KeyboardLayoutAdapter(getActivity(), data));
-    }
-
-    @Override
-    public void onLoaderReset(Loader<KeyboardLayout[]> loader) {
-        setListAdapter(null);
-    }
-
-    private static final class KeyboardLayoutAdapter
-            extends ArrayAdapter<KeyboardLayout> {
-        private LayoutInflater mInflater;
-
-        public KeyboardLayoutAdapter(Context context, KeyboardLayout[] list) {
-            super(context, android.R.layout.simple_list_item_2, list);
-            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            View view = convertView;
-            if (view == null) {
-                view = mInflater.inflate(android.R.layout.simple_list_item_2, parent, false);
-            }
-
-            KeyboardLayout item = getItem(position);
-            TextView headline = (TextView) view.findViewById(android.R.id.text1);
-            TextView subText = (TextView) view.findViewById(android.R.id.text2);
-            headline.setText(item.getLabel());
-            subText.setText(item.getCollection());
-            return view;
-        }
-    }
-
-    private static final class KeyboardLayoutLoader
-            extends AsyncTaskLoader<KeyboardLayout[]> {
-        public KeyboardLayoutLoader(Context context) {
-            super(context);
-        }
-
-        @Override
-        public KeyboardLayout[] loadInBackground() {
-            InputManager im = (InputManager)getContext().getSystemService(Context.INPUT_SERVICE);
-            KeyboardLayout[] list = im.getKeyboardLayouts();
-            KeyboardLayout[] listWithDefault = new KeyboardLayout[list.length + 1];
-            listWithDefault[0] = new KeyboardLayout(null,
-                    getContext().getString(R.string.keyboard_layout_default_label), "");
-            System.arraycopy(list, 0, listWithDefault, 1, list.length);
-            Arrays.sort(listWithDefault);
-            return listWithDefault;
-        }
-
-        @Override
-        protected void onStartLoading() {
-            super.onStartLoading();
-            forceLoad();
-        }
-
-        @Override
-        protected void onStopLoading() {
-            super.onStopLoading();
-            cancelLoad();
-        }
-    }
-}
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java
new file mode 100644
index 0000000..932dd10
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java
@@ -0,0 +1,154 @@
+/*
+ * 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 com.android.settings.SettingsPreferenceFragment;
+
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.hardware.input.InputManager.InputDeviceListener;
+import android.hardware.input.KeyboardLayout;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.view.InputDevice;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class KeyboardLayoutPickerFragment extends SettingsPreferenceFragment
+        implements InputDeviceListener {
+    private String mInputDeviceDescriptor;
+    private int mInputDeviceId = -1;
+    private InputManager mIm;
+    private KeyboardLayout[] mKeyboardLayouts;
+    private HashMap<CheckBoxPreference, KeyboardLayout> mPreferenceMap =
+            new HashMap<CheckBoxPreference, KeyboardLayout>();
+
+    /**
+     * 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 onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mInputDeviceDescriptor = getActivity().getIntent().getStringExtra(
+                EXTRA_INPUT_DEVICE_DESCRIPTOR);
+        if (mInputDeviceDescriptor == null) {
+            getActivity().finish();
+        }
+
+        mIm = (InputManager)getSystemService(Context.INPUT_SERVICE);
+        mKeyboardLayouts = mIm.getKeyboardLayouts();
+        Arrays.sort(mKeyboardLayouts);
+        setPreferenceScreen(createPreferenceHierarchy());
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        mIm.registerInputDeviceListener(this, null);
+
+        InputDevice inputDevice = mIm.getInputDeviceByDescriptor(mInputDeviceDescriptor);
+        if (inputDevice == null) {
+            getActivity().finish();
+            return;
+        }
+        mInputDeviceId = inputDevice.getId();
+
+        updateCheckedState();
+    }
+
+    @Override
+    public void onPause() {
+        mIm.unregisterInputDeviceListener(this);
+        mInputDeviceId = -1;
+
+        super.onPause();
+    }
+
+    @Override
+    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
+            Preference preference) {
+        if (preference instanceof CheckBoxPreference) {
+            CheckBoxPreference checkboxPref = (CheckBoxPreference)preference;
+            KeyboardLayout layout = mPreferenceMap.get(checkboxPref);
+            if (layout != null) {
+                boolean checked = checkboxPref.isChecked();
+                if (checked) {
+                    mIm.addKeyboardLayoutForInputDevice(mInputDeviceDescriptor,
+                            layout.getDescriptor());
+                } else {
+                    mIm.removeKeyboardLayoutForInputDevice(mInputDeviceDescriptor,
+                            layout.getDescriptor());
+                }
+                return true;
+            }
+        }
+        return super.onPreferenceTreeClick(preferenceScreen, preference);
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+            updateCheckedState();
+        }
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+            getActivity().finish();
+        }
+    }
+
+    private PreferenceScreen createPreferenceHierarchy() {
+        PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity());
+        Context context = getActivity();
+
+        for (KeyboardLayout layout : mKeyboardLayouts) {
+            CheckBoxPreference pref = new CheckBoxPreference(context);
+            pref.setTitle(layout.getLabel());
+            pref.setSummary(layout.getCollection());
+            root.addPreference(pref);
+            mPreferenceMap.put(pref, layout);
+        }
+        return root;
+    }
+
+    private void updateCheckedState() {
+        String[] enabledKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(
+                mInputDeviceDescriptor);
+        Arrays.sort(enabledKeyboardLayouts);
+
+        for (Map.Entry<CheckBoxPreference, KeyboardLayout> entry : mPreferenceMap.entrySet()) {
+            entry.getKey().setChecked(Arrays.binarySearch(enabledKeyboardLayouts,
+                    entry.getValue().getDescriptor()) >= 0);
+        }
+    }
+}