Two line item for the IME switcher dialog.

bug: 5098770
Change-Id: I2b955973e7f223d8c98d8dac6aaa657a7a31b555
diff --git a/core/res/res/layout/simple_list_item_2_single_choice.xml b/core/res/res/layout/simple_list_item_2_single_choice.xml
new file mode 100644
index 0000000..90dfe37
--- /dev/null
+++ b/core/res/res/layout/simple_list_item_2_single_choice.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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="horizontal"
+    android:gravity="center_vertical"
+    android:paddingLeft="16dip"
+    android:paddingRight="12dip"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall">
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:gravity="center_vertical">
+        <TextView android:id="@android:id/text1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorAlertDialogListItem"
+            android:gravity="center_vertical|left"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+        />
+        <TextView android:id="@android:id/text2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorAlertDialogListItem"
+            android:gravity="center_vertical|left"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+        />
+    </LinearLayout>
+    <RadioButton
+        android:id="@+id/radio"
+        android:layout_width="35dip"
+        android:layout_height="wrap_content"
+        android:paddingRight="12dip"
+        android:gravity="center_vertical"
+        android:focusable="false"
+        android:clickable="false"
+    />
+</LinearLayout>
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 0e1a1e3..05a7eb2 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -80,6 +80,9 @@
 import android.util.Slog;
 import android.util.Xml;
 import android.view.IWindowManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
@@ -87,6 +90,9 @@
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
+import android.widget.ArrayAdapter;
+import android.widget.RadioButton;
+import android.widget.TextView;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -337,11 +343,10 @@
     int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
     int mImeWindowVis;
 
-    AlertDialog.Builder mDialogBuilder;
-    AlertDialog mSwitchingDialog;
-    InputMethodInfo[] mIms;
-    CharSequence[] mItems;
-    int[] mSubtypeIds;
+    private AlertDialog.Builder mDialogBuilder;
+    private AlertDialog mSwitchingDialog;
+    private InputMethodInfo[] mIms;
+    private int[] mSubtypeIds;
 
     class SettingsObserver extends ContentObserver {
         SettingsObserver(Handler handler) {
@@ -1148,7 +1153,7 @@
                             ? TextUtils.concat(mCurrentSubtype.getDisplayName(mContext,
                                         imi.getPackageName(), imi.getServiceInfo().applicationInfo),
                                                 (TextUtils.isEmpty(imiLabel) ?
-                                                        "" : " (" + imiLabel + ")"))
+                                                        "" : " - " + imiLabel))
                             : imiLabel;
 
                     mImeSwitcherNotification.setLatestEventInfo(
@@ -2073,8 +2078,7 @@
 
             sortedImmis.putAll(immis);
 
-            final ArrayList<Pair<CharSequence, Pair<InputMethodInfo, Integer>>> imList =
-                    new ArrayList<Pair<CharSequence, Pair<InputMethodInfo, Integer>>>();
+            final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
 
             for (InputMethodInfo imi : sortedImmis.keySet()) {
                 if (imi == null) continue;
@@ -2084,7 +2088,7 @@
                     enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
                 }
                 ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
-                final CharSequence label = imi.loadLabel(pm);
+                final CharSequence imeLabel = imi.loadLabel(pm);
                 if (showSubtypes && enabledSubtypeSet.size() > 0) {
                     final int subtypeCount = imi.getSubtypeCount();
                     if (DEBUG) {
@@ -2096,13 +2100,10 @@
                         // We show all enabled IMEs and subtypes when an IME is shown.
                         if (enabledSubtypeSet.contains(subtypeHashCode)
                                 && ((mInputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
-                            final CharSequence title;
-                            final String mode = subtype.getMode();
-                            title = TextUtils.concat(subtype.getDisplayName(context,
-                                    imi.getPackageName(), imi.getServiceInfo().applicationInfo),
-                                    (TextUtils.isEmpty(label) ? "" : " (" + label + ")"));
-                            imList.add(new Pair<CharSequence, Pair<InputMethodInfo, Integer>>(
-                                    title, new Pair<InputMethodInfo, Integer>(imi, j)));
+                            final CharSequence subtypeLabel = subtype.getDisplayName(context,
+                                    imi.getPackageName(), imi.getServiceInfo().applicationInfo);
+                            imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j));
+
                             // Removing this subtype from enabledSubtypeSet because we no longer
                             // need to add an entry of this subtype to imList to avoid duplicated
                             // entries.
@@ -2110,23 +2111,18 @@
                         }
                     }
                 } else {
-                    imList.add(new Pair<CharSequence, Pair<InputMethodInfo, Integer>>(
-                            label, new Pair<InputMethodInfo, Integer>(imi, NOT_A_SUBTYPE_ID)));
+                    imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID));
                 }
             }
 
             final int N = imList.size();
-            mItems = new CharSequence[N];
-            for (int i = 0; i < N; ++i) {
-                mItems[i] = imList.get(i).first;
-            }
             mIms = new InputMethodInfo[N];
             mSubtypeIds = new int[N];
             int checkedItem = 0;
             for (int i = 0; i < N; ++i) {
-                Pair<InputMethodInfo, Integer> value = imList.get(i).second;
-                mIms[i] = value.first;
-                mSubtypeIds[i] = value.second;
+                final ImeSubtypeListItem item = imList.get(i);
+                mIms[i] = item.mImi;
+                mSubtypeIds[i] = item.mSubtypeId;
                 if (mIms[i].getId().equals(lastInputMethodId)) {
                     int subtypeId = mSubtypeIds[i];
                     if ((subtypeId == NOT_A_SUBTYPE_ID)
@@ -2137,14 +2133,7 @@
                 }
             }
 
-            AlertDialog.OnClickListener adocl = new AlertDialog.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    hideInputMethodMenu();
-                }
-            };
-
-            TypedArray a = context.obtainStyledAttributes(null,
+            final TypedArray a = context.obtainStyledAttributes(null,
                     com.android.internal.R.styleable.DialogPreference,
                     com.android.internal.R.attr.alertDialogStyle, 0);
             mDialogBuilder = new AlertDialog.Builder(context)
@@ -2159,7 +2148,11 @@
                             com.android.internal.R.styleable.DialogPreference_dialogTitle));
             a.recycle();
 
-            mDialogBuilder.setSingleChoiceItems(mItems, checkedItem,
+            final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(context,
+                    com.android.internal.R.layout.simple_list_item_2_single_choice, imList,
+                    checkedItem);
+
+            mDialogBuilder.setSingleChoiceItems(adapter, checkedItem,
                     new AlertDialog.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog, int which) {
@@ -2201,6 +2194,59 @@
         }
     }
 
+    private static class ImeSubtypeListItem {
+        public final CharSequence mImeName;
+        public final CharSequence mSubtypeName;
+        public final InputMethodInfo mImi;
+        public final int mSubtypeId;
+        public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
+                InputMethodInfo imi, int subtypeId) {
+            mImeName = imeName;
+            mSubtypeName = subtypeName;
+            mImi = imi;
+            mSubtypeId = subtypeId;
+        }
+    }
+
+    private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
+        private final LayoutInflater mInflater;
+        private final int mTextViewResourceId;
+        private final List<ImeSubtypeListItem> mItemsList;
+        private final int mCheckedItem;
+        public ImeSubtypeListAdapter(Context context, int textViewResourceId,
+                List<ImeSubtypeListItem> itemsList, int checkedItem) {
+            super(context, textViewResourceId, itemsList);
+            mTextViewResourceId = textViewResourceId;
+            mItemsList = itemsList;
+            mCheckedItem = checkedItem;
+            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final View view = convertView != null ? convertView
+                    : mInflater.inflate(mTextViewResourceId, null);
+            if (position < 0 || position >= mItemsList.size()) return view;
+            final ImeSubtypeListItem item = mItemsList.get(position);
+            final CharSequence imeName = item.mImeName;
+            final CharSequence subtypeName = item.mSubtypeName;
+            final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
+            final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
+            if (TextUtils.isEmpty(subtypeName)) {
+                firstTextView.setText(imeName);
+                secondTextView.setVisibility(View.GONE);
+            } else {
+                firstTextView.setText(subtypeName);
+                secondTextView.setText(imeName);
+                secondTextView.setVisibility(View.VISIBLE);
+            }
+            final RadioButton radioButton =
+                    (RadioButton)view.findViewById(com.android.internal.R.id.radio);
+            radioButton.setChecked(position == mCheckedItem);
+            return view;
+        }
+    }
+
     void hideInputMethodMenu() {
         synchronized (mMethodMap) {
             hideInputMethodMenuLocked();
@@ -2216,7 +2262,6 @@
         }
 
         mDialogBuilder = null;
-        mItems = null;
         mIms = null;
     }