Merge "Several improvements and fixes in restrictions UI" into jb-mr2-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8a779c9..4e8ef57 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -802,8 +802,10 @@
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.settings.APP_OPS_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <!-- Not yet ready to expose.
                 <category android:name="android.intent.category.VOICE_LAUNCH" />
                 <category android:name="com.android.settings.SHORTCUT" />
+                -->
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                 android:value="com.android.settings.applications.AppOpsSummary" />
@@ -1579,7 +1581,7 @@
 
         <receiver android:name=".widget.SettingsAppWidgetProvider"
                 android:label="@string/gadget_title"
-                android:exported="true"
+                android:exported="false"
                 android:enabled="@bool/has_powercontrol_widget">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
diff --git a/res/layout/enable_accessibility_service_dialog_content.xml b/res/layout/enable_accessibility_service_dialog_content.xml
new file mode 100644
index 0000000..fbeeb27
--- /dev/null
+++ b/res/layout/enable_accessibility_service_dialog_content.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:scrollbarStyle="outsideOverlay"
+    android:gravity="top">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingStart="16dip"
+        android:paddingEnd="16dip" >
+
+        <TextView android:id="@+id/capabilities_header"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:padding="10dip"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <LinearLayout android:id="@+id/capabilities"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:padding="10dip" />
+
+    </LinearLayout>
+
+</ScrollView>
diff --git a/res/layout/user_dictionary_add_word.xml b/res/layout/user_dictionary_add_word.xml
index d8b8694..3624dad 100644
--- a/res/layout/user_dictionary_add_word.xml
+++ b/res/layout/user_dictionary_add_word.xml
@@ -45,6 +45,7 @@
             android:layout_marginStart="8dip"
             android:layout_marginBottom="8dip"
             android:layout_marginTop="8dip"
+            android:hint="@string/user_dict_settings_add_word_hint"
             android:inputType="textNoSuggestions"
             android:imeOptions="flagNoFullscreen">
     <requestFocus />
diff --git a/res/layout/user_dictionary_add_word_fullscreen.xml b/res/layout/user_dictionary_add_word_fullscreen.xml
index f29c669..b72886f 100644
--- a/res/layout/user_dictionary_add_word_fullscreen.xml
+++ b/res/layout/user_dictionary_add_word_fullscreen.xml
@@ -33,6 +33,7 @@
             android:layout_marginStart="8dip"
             android:layout_marginBottom="8dip"
             android:layout_marginTop="8dip"
+            android:hint="@string/user_dict_settings_add_word_hint"
             android:inputType="textNoSuggestions"
             android:imeOptions="flagNoFullscreen">
     <requestFocus />
@@ -56,6 +57,7 @@
               android:layout_marginStart="8dip"
               android:layout_marginBottom="8dip"
               android:layout_marginTop="8dip"
+              android:hint="@string/user_dict_settings_add_shortcut_hint"
               android:inputType="textNoSuggestions"
               android:imeOptions="flagNoFullscreen" />
     <TextView android:id="@+id/user_dictionary_add_locale_label"
diff --git a/res/layout/wifi_ap_dialog.xml b/res/layout/wifi_ap_dialog.xml
index d458cd3..a2146c6 100644
--- a/res/layout/wifi_ap_dialog.xml
+++ b/res/layout/wifi_ap_dialog.xml
@@ -46,6 +46,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:singleLine="true"
+                    android:hint="@string/wifi_ssid_hint"
                     android:inputType="textNoSuggestions"
                     android:maxLength="32" />
 
diff --git a/res/layout/wifi_config_ui_for_setup_wizard.xml b/res/layout/wifi_config_ui_for_setup_wizard.xml
index fef10b3..143d9ee 100644
--- a/res/layout/wifi_config_ui_for_setup_wizard.xml
+++ b/res/layout/wifi_config_ui_for_setup_wizard.xml
@@ -86,6 +86,7 @@
                     android:layout_width="368dip"
                     android:layout_height="wrap_content"
                     android:singleLine="true"
+                    android:hint="@string/wifi_ssid_hint"
                     android:inputType="textNoSuggestions"
                     android:textAppearance="?android:attr/textAppearanceMedium"
                     android:textSize="20sp" />
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index 7a7d0b0..cd968b1 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -40,6 +40,7 @@
 
                 <EditText android:id="@+id/ssid"
                         style="@style/wifi_item_edit_content"
+                        android:hint="@string/wifi_ssid_hint"
                         android:maxLength="32"
                         android:singleLine="true"
                         android:inputType="textNoSuggestions" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7217329..6a54d7a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1385,6 +1385,8 @@
     <string name="wifi_wps_failed_overlap">Another WPS session was detected. Please try again in a few minutes.</string>
     <!-- Label for the SSID of the network -->
     <string name="wifi_ssid">Network SSID</string>
+    <!-- Hint for a text field to enter the SSID of a hidden wifi network. [CHAR LIMIT=35] -->
+    <string name="wifi_ssid_hint">Enter the SSID</string>
     <!-- Label for the security of the connection -->
     <string name="wifi_security">Security</string>
     <!-- Label for the signal strength of the connection -->
@@ -2949,6 +2951,10 @@
     <string name="user_dict_settings_add_shortcut_option_name">Shortcut:</string>
     <!-- User dictionary settings. Label to put before the language field. [CHAR LIMIT=20] -->
     <string name="user_dict_settings_add_locale_option_name">Language:</string>
+    <!-- User dictionary settings. Hint for the text field to type the word to add to the user dictionary. [CHAR LIMIT=35] -->
+    <string name="user_dict_settings_add_word_hint">Type a word</string>
+    <!-- User dictionary settings. Hint for the text field to type the optional shortcut to add to the user dictionary. [CHAR LIMIT=35] -->
+    <string name="user_dict_settings_add_shortcut_hint">Optional shortcut</string>
     <!-- User dictionary settings. The title of the dialog to edit an existing word in the user dictionary. -->
     <string name="user_dict_settings_edit_dialog_title">Edit word</string>
     <!-- User dictionary settings. The title of the context menu item to edit the current word -->
@@ -3181,30 +3187,24 @@
     <!-- Summary for the disabled state of an accessiblity feature. [CHAR LIMIT=10] -->
     <string name="accessibility_feature_state_off">Off</string>
 
-     <!-- Title for a warning message about security implications of enabling an accessibility service,
-         displayed as a dialog message when the user selects to enable an accessibility service (tablet). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_service_security_warning_title">Use
+    <!-- Title for a warning about security implications of enabling an accessibility
+         service. [CHAR LIMIT=NONE] -->
+    <string name="enable_service_title">Use
          <xliff:g id="service" example="TalkBack">%1$s</xliff:g>?</string>
-    <!-- Summary for a warning message about security implications of enabling an accessibility service,
-         displayed as a dialog message when the user selects to enable an accessibility service (tablet). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_service_security_warning_summary" product="tablet">
-            <xliff:g id="accessibility_service_name">%1$s</xliff:g> can
-            collect all of the text you type, except passwords. This includes personal data such as credit card
-            numbers. It can also collect data about your interactions with the tablet.</string>
-    <!-- Summary for a warning message about security implications of enabling an accessibility service,
-         displayed as a dialog message when the user selects to enable an accessibility service (phone). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_service_security_warning_summary" product="default">
-            <xliff:g id="accessibility_service_name">%1$s</xliff:g> can
-            collect all of the text you type, except passwords. This includes personal data such as credit card
-            numbers. It can also collect data about your interactions with the phone.</string>
+    <!-- Title for the list of capabilities of an accessibility service. -->
+    <string name="capabilities_list_title"><xliff:g id="service" example="TalkBack">%1$s</xliff:g>
+        needs to:</string>
 
-    <!-- Title for a warning about disabling an accessibility service displayed as a dialog message when the user
-         selects to disable that service. This avoids accidental disabling. [CHAR LIMIT=NONE] -->
-    <string name="accessibility_service_disable_warning_title">Stop
-         <xliff:g id="service" example="TalkBack">%1$s</xliff:g>?</string>
-    <!-- Summary for a warning about disabling accessibility service displayed as a dialog message when the user
-         selects to disable that service. This avoids accidental disabling. [CHAR LIMIT=NONE] -->
-    <string name="accessibility_service_disable_warning_summary">Touching OK will
+    <!-- Title for the capability of an accessibility service to receive events and keys. -->
+    <string name="capability_title_receiveAccessibilityEvents">Observe your actions</string>
+    <!-- Description for the capability of an accessibility service to receive events and keys. -->
+    <string name="capability_desc_receiveAccessibilityEvents">Receive notifications when you\'re
+        interacting with an app.</string>
+
+    <!-- Title for a warning about disabling an accessibility service. [CHAR LIMIT=NONE] -->
+    <string name="disable_service_title">Stop<xliff:g id="service" example="TalkBack">%1$s</xliff:g>?</string>
+    <!-- Message for a warning about disabling accessibility service. [CHAR LIMIT=NONE] -->
+    <string name="disable_service_message">Touching OK will
         stop <xliff:g id="service" example="TalkBack">%1$s</xliff:g>.</string>
 
     <!-- Title for the prompt shown as a placeholder if no accessibility serivices are installed. [CHAR LIMIT=50] -->
diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java
index ec00892..fb0a429 100644
--- a/src/com/android/settings/AccessibilitySettings.java
+++ b/src/com/android/settings/AccessibilitySettings.java
@@ -50,12 +50,14 @@
 import android.view.Gravity;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.Switch;
 import android.widget.TextView;
@@ -118,13 +120,9 @@
     private static final String EXTRA_CHECKED = "checked";
     private static final String EXTRA_TITLE = "title";
     private static final String EXTRA_SUMMARY = "summary";
-    private static final String EXTRA_ENABLE_WARNING_TITLE = "enable_warning_title";
-    private static final String EXTRA_ENABLE_WARNING_MESSAGE = "enable_warning_message";
-    private static final String EXTRA_DISABLE_WARNING_TITLE = "disable_warning_title";
-    private static final String EXTRA_DISABLE_WARNING_MESSAGE = "disable_warning_message";
     private static final String EXTRA_SETTINGS_TITLE = "settings_title";
     private static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
-    private static final String EXTRA_SERVICE_COMPONENT_NAME = "service_component_name";
+    private static final String EXTRA_ACCESSIBILITY_SERVICE_INFO = "accessibility_service_info";
 
     // Dialog IDs.
     private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 1;
@@ -409,20 +407,6 @@
             }
             extras.putString(EXTRA_SUMMARY, description);
 
-            CharSequence applicationLabel = info.getResolveInfo().loadLabel(getPackageManager());
-
-            extras.putString(EXTRA_ENABLE_WARNING_TITLE, getString(
-                    R.string.accessibility_service_security_warning_title, applicationLabel));
-            extras.putString(EXTRA_ENABLE_WARNING_MESSAGE, getString(
-                    R.string.accessibility_service_security_warning_summary, applicationLabel));
-
-            extras.putString(EXTRA_DISABLE_WARNING_TITLE, getString(
-                    R.string.accessibility_service_disable_warning_title,
-                    applicationLabel));
-            extras.putString(EXTRA_DISABLE_WARNING_MESSAGE, getString(
-                    R.string.accessibility_service_disable_warning_summary,
-                    applicationLabel));
-
             String settingsClassName = info.getSettingsActivityName();
             if (!TextUtils.isEmpty(settingsClassName)) {
                 extras.putString(EXTRA_SETTINGS_TITLE,
@@ -432,7 +416,7 @@
                                 settingsClassName).flattenToString());
             }
 
-            extras.putString(EXTRA_SERVICE_COMPONENT_NAME, componentName.flattenToString());
+            extras.putParcelable(EXTRA_ACCESSIBILITY_SERVICE_INFO, info);
 
             mServicesCategory.addPreference(preference);
         }
@@ -698,10 +682,7 @@
             }
         };
 
-        private CharSequence mEnableWarningTitle;
-        private CharSequence mEnableWarningMessage;
-        private CharSequence mDisableWarningTitle;
-        private CharSequence mDisableWarningMessage;
+        private AccessibilityServiceInfo mAccessibilityServiceInfo;
 
         private String mComponentName;
 
@@ -767,32 +748,113 @@
                     Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0);
         }
 
+//        extras.putString(EXTRA_ENABLE_WARNING_TITLE, getString(
+//                R.string.accessibility_service_security_warning_title, applicationLabel));
+//        extras.putString(EXTRA_ENABLE_WARNING_MESSAGE, getString(
+//                R.string.accessibility_service_security_warning_summary, applicationLabel));
+//
+//        extras.putString(EXTRA_DISABLE_WARNING_TITLE, getString(
+//                R.string.accessibility_service_disable_warning_title,
+//                applicationLabel));
+//        extras.putString(EXTRA_DISABLE_WARNING_MESSAGE, getString(
+//                R.string.accessibility_service_disable_warning_summary,
+//                applicationLabel));
+
         @Override
         public Dialog onCreateDialog(int dialogId) {
-            CharSequence title = null;
-            CharSequence message = null;
             switch (dialogId) {
                 case DIALOG_ID_ENABLE_WARNING:
                     mShownDialogId = DIALOG_ID_ENABLE_WARNING;
-                    title = mEnableWarningTitle;
-                    message = mEnableWarningMessage;
-                    break;
+                    return new AlertDialog.Builder(getActivity())
+                        .setTitle(getString(R.string.enable_service_title,
+                                mAccessibilityServiceInfo.getResolveInfo()
+                                .loadLabel(getPackageManager())))
+                        .setIconAttribute(android.R.attr.alertDialogIcon)
+                        .setView(createEnableDialogContentView())
+                        .setCancelable(true)
+                        .setPositiveButton(android.R.string.ok, this)
+                        .setNegativeButton(android.R.string.cancel, this)
+                        .create();
                 case DIALOG_ID_DISABLE_WARNING:
                     mShownDialogId = DIALOG_ID_DISABLE_WARNING;
-                    title = mDisableWarningTitle;
-                    message = mDisableWarningMessage;
-                    break;
+                    return new AlertDialog.Builder(getActivity())
+                        .setTitle(getString(R.string.disable_service_title,
+                                mAccessibilityServiceInfo.getResolveInfo()
+                                .loadLabel(getPackageManager())))
+                        .setIconAttribute(android.R.attr.alertDialogIcon)
+                        .setMessage(getString(R.string.disable_service_message,
+                                mAccessibilityServiceInfo.getResolveInfo()
+                                .loadLabel(getPackageManager())))
+                        .setCancelable(true)
+                        .setPositiveButton(android.R.string.ok, this)
+                        .setNegativeButton(android.R.string.cancel, this)
+                        .create();
                 default:
                     throw new IllegalArgumentException();
             }
-            return new AlertDialog.Builder(getActivity())
-                    .setTitle(title)
-                    .setIconAttribute(android.R.attr.alertDialogIcon)
-                    .setMessage(message)
-                    .setCancelable(true)
-                    .setPositiveButton(android.R.string.ok, this)
-                    .setNegativeButton(android.R.string.cancel, this)
-                    .create();
+        }
+
+        private View createEnableDialogContentView() {
+            LayoutInflater inflater = (LayoutInflater) getSystemService(
+                    Context.LAYOUT_INFLATER_SERVICE);
+
+            View content = inflater.inflate(R.layout.enable_accessibility_service_dialog_content,
+                    null);
+
+            TextView capabilitiesHeaderView = (TextView) content.findViewById(
+                    R.id.capabilities_header);
+            capabilitiesHeaderView.setText(getString(R.string.capabilities_list_title,
+                    mAccessibilityServiceInfo.getResolveInfo().loadLabel(getPackageManager())));
+
+            LinearLayout capabilitiesView = (LinearLayout) content.findViewById(R.id.capabilities);
+
+            // This capability is implicit for all services.
+            View capabilityView = inflater.inflate(
+                    com.android.internal.R.layout.app_permission_item_old, null);
+
+            ImageView imageView = (ImageView) capabilityView.findViewById(
+                    com.android.internal.R.id.perm_icon);
+            imageView.setImageDrawable(getResources().getDrawable(
+                    com.android.internal.R.drawable.ic_text_dot));
+
+            TextView labelView = (TextView) capabilityView.findViewById(
+                    com.android.internal.R.id.permission_group);
+            labelView.setText(getString(R.string.capability_title_receiveAccessibilityEvents));
+
+            TextView descriptionView = (TextView) capabilityView.findViewById(
+                    com.android.internal.R.id.permission_list);
+            descriptionView.setText(getString(R.string.capability_desc_receiveAccessibilityEvents));
+
+            List<AccessibilityServiceInfo.CapabilityInfo> capabilities =
+                    mAccessibilityServiceInfo.getCapabilityInfos();
+
+            capabilitiesView.addView(capabilityView);
+
+            // Service specific capabilities.
+            final int capabilityCount = capabilities.size();
+            for (int i = 0; i < capabilityCount; i++) {
+                AccessibilityServiceInfo.CapabilityInfo capability = capabilities.get(i);
+
+                capabilityView = inflater.inflate(
+                        com.android.internal.R.layout.app_permission_item_old, null);
+
+                imageView = (ImageView) capabilityView.findViewById(
+                        com.android.internal.R.id.perm_icon);
+                imageView.setImageDrawable(getResources().getDrawable(
+                        com.android.internal.R.drawable.ic_text_dot));
+
+                labelView = (TextView) capabilityView.findViewById(
+                        com.android.internal.R.id.permission_group);
+                labelView.setText(getString(capability.titleResId));
+
+                descriptionView = (TextView) capabilityView.findViewById(
+                        com.android.internal.R.id.permission_list);
+                descriptionView.setText(getString(capability.descResId));
+
+                capabilitiesView.addView(capabilityView);
+            }
+
+            return content;
         }
 
         @Override
@@ -823,23 +885,15 @@
                 @Override
                 public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
                     if (checked) {
-                        if (!TextUtils.isEmpty(mEnableWarningMessage)) {
-                            toggleSwitch.setCheckedInternal(false);
-                            getArguments().putBoolean(EXTRA_CHECKED, false);
-                            showDialog(DIALOG_ID_ENABLE_WARNING);
-                            return true;
-                        }
-                        onPreferenceToggled(mPreferenceKey, true);
+                        toggleSwitch.setCheckedInternal(false);
+                        getArguments().putBoolean(EXTRA_CHECKED, false);
+                        showDialog(DIALOG_ID_ENABLE_WARNING);
                     } else {
-                        if (!TextUtils.isEmpty(mDisableWarningMessage)) {
-                            toggleSwitch.setCheckedInternal(true);
-                            getArguments().putBoolean(EXTRA_CHECKED, true);
-                            showDialog(DIALOG_ID_DISABLE_WARNING);
-                            return true;
-                        }
-                        onPreferenceToggled(mPreferenceKey, false);
+                        toggleSwitch.setCheckedInternal(true);
+                        getArguments().putBoolean(EXTRA_CHECKED, true);
+                        showDialog(DIALOG_ID_DISABLE_WARNING);
                     }
-                    return false;
+                    return true;
                 }
             });
         }
@@ -859,20 +913,12 @@
                     setHasOptionsMenu(true);
                 }
             }
-            // Enable warning title.
-            mEnableWarningTitle = arguments.getCharSequence(
-                    AccessibilitySettings.EXTRA_ENABLE_WARNING_TITLE);
-            // Enable warning message.
-            mEnableWarningMessage = arguments.getCharSequence(
-                    AccessibilitySettings.EXTRA_ENABLE_WARNING_MESSAGE);
-            // Disable warning title.
-            mDisableWarningTitle = arguments.getString(
-                    AccessibilitySettings.EXTRA_DISABLE_WARNING_TITLE);
-            // Disable warning message.
-            mDisableWarningMessage = arguments.getString(
-                    AccessibilitySettings.EXTRA_DISABLE_WARNING_MESSAGE);
-            // Component name.
-            mComponentName = arguments.getString(EXTRA_SERVICE_COMPONENT_NAME);
+
+            mAccessibilityServiceInfo = arguments.getParcelable(EXTRA_ACCESSIBILITY_SERVICE_INFO);
+
+            ServiceInfo serviceInfo = mAccessibilityServiceInfo.getResolveInfo().serviceInfo;
+            mComponentName = new ComponentName(serviceInfo.packageName,
+                    serviceInfo.name).flattenToString();
         }
     }
 
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
index 940d8d0..9b2a3e8 100755
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
@@ -43,6 +43,8 @@
 import com.android.settings.R;
 import android.view.KeyEvent;
 
+import java.util.Locale;
+
 /**
  * BluetoothPairingDialog asks the user to enter a PIN / Passkey / simple confirmation
  * for pairing with a remote Bluetooth device. It is an activity that appears as a dialog.
@@ -120,7 +122,7 @@
                     Log.e(TAG, "Invalid Confirmation Passkey received, not showing any dialog");
                     return;
                 }
-                mPairingKey = String.format("%06d", passkey);
+                mPairingKey = String.format(Locale.US, "%06d", passkey);
                 createConfirmationDialog(deviceManager);
                 break;
 
diff --git a/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java b/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java
index 13f4435..f3addf3 100644
--- a/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java
+++ b/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java
@@ -36,10 +36,13 @@
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 
 public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment {
     private static final String TAG =InputMethodAndSubtypeEnabler.class.getSimpleName();
@@ -54,6 +57,7 @@
     private String mInputMethodId;
     private String mTitle;
     private String mSystemLocale = "";
+    private Collator mCollator = Collator.getInstance();
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -84,7 +88,9 @@
             }
         }
 
-        mSystemLocale = config.locale.toString();
+        final Locale locale = config.locale;
+        mSystemLocale = locale.toString();
+        mCollator = Collator.getInstance(locale);
         onCreateIMM();
         setPreferenceScreen(createPreferenceHierarchy());
     }
@@ -259,7 +265,7 @@
                         }
                     } else {
                         final CheckBoxPreference chkbxPref = new SubtypeCheckBoxPreference(
-                                context, subtype.getLocale(), mSystemLocale);
+                                context, subtype.getLocale(), mSystemLocale, mCollator);
                         chkbxPref.setKey(imiId + subtype.hashCode());
                         chkbxPref.setTitle(subtypeLabel);
                         subtypePreferences.add(chkbxPref);
@@ -370,9 +376,10 @@
     private static class SubtypeCheckBoxPreference extends CheckBoxPreference {
         private final boolean mIsSystemLocale;
         private final boolean mIsSystemLanguage;
+        private final Collator mCollator;
 
         public SubtypeCheckBoxPreference(
-                Context context, String subtypeLocale, String systemLocale) {
+                Context context, String subtypeLocale, String systemLocale, Collator collator) {
             super(context);
             if (TextUtils.isEmpty(subtypeLocale)) {
                 mIsSystemLocale = false;
@@ -382,6 +389,7 @@
                 mIsSystemLanguage = mIsSystemLocale
                         || subtypeLocale.startsWith(systemLocale.substring(0, 2));
             }
+            mCollator = collator;
         }
 
         @Override
@@ -411,10 +419,10 @@
                 if (TextUtils.isEmpty(t1)) {
                     return -1;
                 }
-                return t0.toString().compareTo(t1.toString());
+                return mCollator.compare(t0.toString(), t1.toString());
             } else {
                 Log.w(TAG, "Illegal preference type.");
-                return -1;
+                return super.compareTo(p);
             }
         }
     }
diff --git a/src/com/android/settings/inputmethod/InputMethodPreference.java b/src/com/android/settings/inputmethod/InputMethodPreference.java
index f064c08..56b6e67 100644
--- a/src/com/android/settings/inputmethod/InputMethodPreference.java
+++ b/src/com/android/settings/inputmethod/InputMethodPreference.java
@@ -28,6 +28,7 @@
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.preference.CheckBoxPreference;
+import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -42,11 +43,11 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import java.text.Collator;
 import java.util.Comparator;
 import java.util.List;
 
-public class InputMethodPreference extends CheckBoxPreference
-        implements Comparator<InputMethodPreference> {
+public class InputMethodPreference extends CheckBoxPreference {
     private static final String TAG = InputMethodPreference.class.getSimpleName();
     private final SettingsPreferenceFragment mFragment;
     private final InputMethodInfo mImi;
@@ -54,6 +55,7 @@
     private final Intent mSettingsIntent;
     private final boolean mAlwaysChecked;
     private final boolean mIsSystemIme;
+    private final Collator mCollator;
 
     private AlertDialog mDialog = null;
     private ImageView mInputMethodSettingsButton;
@@ -95,6 +97,7 @@
         if (mAlwaysChecked) {
             setEnabled(false);
         }
+        mCollator = Collator.getInstance(fragment.getResources().getConfiguration().locale);
     }
 
     @Override
@@ -276,13 +279,26 @@
     }
 
     @Override
-    public int compare(InputMethodPreference arg0, InputMethodPreference arg1) {
-        if (arg0.isEnabled() == arg0.isEnabled()) {
-            return arg0.mImi.getId().compareTo(arg1.mImi.getId());
-        } else {
-            // Prefer system IMEs
-            return arg0.isEnabled() ? 1 : -1;
+    public int compareTo(Preference p) {
+        if (!(p instanceof InputMethodPreference)) {
+            return super.compareTo(p);
         }
+        final InputMethodPreference imp = (InputMethodPreference) p;
+        final boolean priority0 = mIsSystemIme && mAlwaysChecked;
+        final boolean priority1 = imp.mIsSystemIme && imp.mAlwaysChecked;
+        if (priority0 == priority1) {
+            final CharSequence t0 = getTitle();
+            final CharSequence t1 = imp.getTitle();
+            if (TextUtils.isEmpty(t0)) {
+                return 1;
+            }
+            if (TextUtils.isEmpty(t1)) {
+                return -1;
+            }
+            return mCollator.compare(t0.toString(), t1.toString());
+        }
+        // Prefer always checked system IMEs
+        return priority0 ? -1 : 1;
     }
 
     private void saveImeSettings() {