Store the current IME's token in the system bar for changing the current IME to a shortcut IME from the system bar

Bug: 3212206
Bug: 3201828

- Added a shortcut IME button. This will be used for calling a shortcut IME (e.g. Voice input)
- Made the positions of IME buttons left aligned
- IME token is required to change IME because of the security reasons.

Change-Id: I48ba5e2509b3aa1bfd2394f9201427fa6b93c6d3
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index f87ca3e..1cc068f 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -32,6 +32,6 @@
     void animateCollapse();
     void setLightsOn(boolean on);
     void setMenuKeyVisible(boolean visible);
-    void setIMEButtonVisible(boolean visible);
+    void setIMEButtonVisible(in IBinder token, boolean visible);
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 19666fd..f86b72d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -32,13 +32,13 @@
     void removeIcon(String slot);
     void setActiveWindowIsFullscreen(boolean fullscreen);
     void setMenuKeyVisible(boolean visible);
-    void setIMEButtonVisible(boolean visible);
+    void setIMEButtonVisible(in IBinder token, boolean visible);
 
     // ---- Methods below are for use by the status bar policy services ----
     // You need the STATUS_BAR_SERVICE permission
     void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList,
             out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications,
-            out int[] switches);
+            out int[] switches, out List<IBinder> binders);
     void onPanelRevealed();
     void onNotificationClick(String pkg, String tag, int id);
     void onNotificationError(String pkg, String tag, int id,
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 488dbba..d4e9c53 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -167,11 +167,19 @@
                     />
             </com.android.systemui.statusbar.tablet.ShirtPocket>
             <com.android.systemui.statusbar.tablet.InputMethodButton
-                android:id="@+id/imeButton"
+                android:id="@+id/imeSwitchButton"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:layout_marginLeft="8dip"
-                android:src="@drawable/ic_sysbar_ime"
+                android:src="@drawable/ic_sysbar_ime_default"
+                android:visibility="invisible"
+                />
+            <com.android.systemui.statusbar.tablet.InputMethodButton
+                android:id="@+id/imeShortcutButton"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginLeft="8dip"
+                android:src="@drawable/ic_sysbar_ime_default"
                 android:visibility="invisible"
                 />
         </LinearLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index ed2ed1c..37939df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -82,7 +82,7 @@
         public void animateCollapse();
         public void setLightsOn(boolean on);
         public void setMenuKeyVisible(boolean visible);
-        public void setIMEButtonVisible(boolean visible);
+        public void setIMEButtonVisible(IBinder token, boolean visible);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -165,10 +165,10 @@
         }
     }
 
-    public void setIMEButtonVisible(boolean visible) {
+    public void setIMEButtonVisible(IBinder token, boolean visible) {
         synchronized (mList) {
             mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
-            mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, visible ? 1 : 0, 0, null).sendToTarget();
+            mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, visible ? 1 : 0, 0, token).sendToTarget();
         }
     }
 
@@ -233,7 +233,7 @@
                     mCallbacks.setMenuKeyVisible(msg.arg1 != 0);
                     break;
                 case MSG_SHOW_IME_BUTTON:
-                    mCallbacks.setIMEButtonVisible(msg.arg1 != 0);
+                    mCallbacks.setIMEButtonVisible((IBinder)msg.obj, msg.arg1 != 0);
                     break;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index 731f6cd..d7f3730 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -65,9 +65,10 @@
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         int[] switches = new int[4];
+        ArrayList<IBinder> binders = new ArrayList<IBinder>();
         try {
             mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
-                    switches);
+                    switches, binders);
         } catch (RemoteException ex) {
             // If the system process isn't there we're doomed anyway.
         }
@@ -75,7 +76,8 @@
         disable(switches[0]);
         setLightsOn(switches[1] != 0);
         setMenuKeyVisible(switches[2] != 0);
-        setIMEButtonVisible(switches[3] != 0);
+        // StatusBarManagerService has a back up of IME token and it's restored here.
+        setIMEButtonVisible(binders.get(0), switches[3] != 0);
 
         // Set up the initial icon state
         int N = iconList.size();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 915fa2f..5391178 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1016,7 +1016,7 @@
 
     // Not supported
     public void setMenuKeyVisible(boolean visible) { }
-    public void setIMEButtonVisible(boolean visible) { }
+    public void setIMEButtonVisible(IBinder token, boolean visible) { }
 
     private class Launcher implements View.OnClickListener {
         private PendingIntent mIntent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
index a025d63..6ebd568 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
@@ -20,6 +20,7 @@
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.IBinder;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
@@ -33,24 +34,39 @@
 import com.android.server.InputMethodManagerService;
 import com.android.systemui.R;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class InputMethodButton extends ImageView {
 
     private static final String  TAG = "StatusBar/InputMethodButton";
     private static final boolean DEBUG = false;
 
-    private boolean mKeyboardShown;
-    private ImageView mIcon;
+    private static final int ID_IME_SWITCH_BUTTON = R.id.imeSwitchButton;
+    private static final int ID_IME_SHORTCUT_BUTTON = R.id.imeShortcutButton;
+
     // other services we wish to talk to
-    private InputMethodManager mImm;
+    private final InputMethodManager mImm;
+    private final int mId;
+    // Cache of InputMethodsInfo
+    private final HashMap<String, InputMethodInfo> mInputMethodsInfo =
+            new HashMap<String, InputMethodInfo>();
+    private ImageView mIcon;
+    private IBinder mToken;
+    private boolean mKeyboardShown;
+    private InputMethodInfo mShortcutInfo;
+    private InputMethodSubtype mShortcutSubtype;
 
     public InputMethodButton(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         mKeyboardShown = false;
+        // Resource Id of the input method button. This id is defined in status_bar.xml
+        mId = getId();
         // IME hookup
-        mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+        mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
         // TODO: read the current icon & visibility state directly from the service
 
         // TODO: register for notifications about changes to visibility & subtype from service
@@ -58,14 +74,24 @@
         setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                mImm.showInputMethodSubtypePicker();
+                switch (mId) {
+                    case ID_IME_SWITCH_BUTTON:
+                        mImm.showInputMethodSubtypePicker();
+                        break;
+                    case ID_IME_SHORTCUT_BUTTON:
+                        if (mToken != null && mShortcutInfo != null) {
+                            mImm.setInputMethodAndSubtype(
+                                    mToken, mShortcutInfo.getId(), mShortcutSubtype);
+                        }
+                        break;
+                }
             }
         });
     }
 
     @Override
     protected void onAttachedToWindow() {
-        mIcon = (ImageView) findViewById(R.id.imeButton);
+        mIcon = (ImageView) findViewById(mId);
 
         refreshStatusIcon(mKeyboardShown);
     }
@@ -73,25 +99,44 @@
     private InputMethodInfo getCurrentInputMethodInfo() {
         String curInputMethodId = Settings.Secure.getString(getContext()
                 .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
-        List<InputMethodInfo> imis = mImm.getEnabledInputMethodList();
-        if (curInputMethodId != null) {
-            for (InputMethodInfo imi: imis) {
-                if (imi.getId().equals(curInputMethodId)) {
-                    return imi;
-                }
+        if (!mInputMethodsInfo.containsKey(curInputMethodId)) {
+            mInputMethodsInfo.clear();
+            List<InputMethodInfo> imis = mImm.getInputMethodList();
+            for (int i = 0; i < imis.size(); ++i) {
+                InputMethodInfo imi = imis.get(i);
+                mInputMethodsInfo.put(imi.getId(), imi);
+            }
+        }
+        return mInputMethodsInfo.get(curInputMethodId);
+    }
+
+    // TODO: Need to show an appropriate drawable for this shortcut button,
+    // if there are two or more shortcut input methods contained in this button.
+    // And need to add other methods to handle multiple shortcuts as appropriate.
+    private Drawable getShortcutInputMethodAndSubtypeDrawable() {
+        Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts =
+                mImm.getShortcutInputMethodsAndSubtypes();
+        if (shortcuts.size() > 0) {
+            for (InputMethodInfo imi: shortcuts.keySet()) {
+                List<InputMethodSubtype> subtypes = shortcuts.get(imi);
+                // TODO: Returns the first found IMI for now. Should handle all shortcuts as
+                // appropriate.
+                mShortcutInfo = imi;
+                // TODO: Pick up the first found subtype for now. Should handle all subtypes
+                // as appropriate.
+                mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null;
+                return getSubtypeIcon(mShortcutInfo, mShortcutSubtype);
             }
         }
         return null;
     }
 
-    private Drawable getCurrentSubtypeIcon() {
+    private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) {
         final PackageManager pm = getContext().getPackageManager();
-        InputMethodInfo imi = getCurrentInputMethodInfo();
-        InputMethodSubtype subtype = mImm.getCurrentInputMethodSubtype();
-        Drawable icon = null;
         if (imi != null) {
             if (DEBUG) {
-                Log.d(TAG, "--- Update icons of IME: " + imi.getPackageName() + "," + subtype);
+                Log.d(TAG, "Update icons of IME: " + imi.getPackageName() + ","
+                        + subtype.getLocale() + "," + subtype.getMode());
             }
             if (subtype != null) {
                 return pm.getDrawable(imi.getPackageName(), subtype.getIconResId(),
@@ -104,7 +149,7 @@
                 try {
                     return pm.getApplicationInfo(imi.getPackageName(), 0).loadIcon(pm);
                 } catch (PackageManager.NameNotFoundException e) {
-                    Log.w(TAG, "Current IME cann't be found: " + imi.getPackageName());
+                    Log.w(TAG, "IME can't be found: " + imi.getPackageName());
                 }
             }
         }
@@ -118,7 +163,18 @@
         } else {
             setVisibility(View.VISIBLE);
         }
-        Drawable icon = getCurrentSubtypeIcon();
+        Drawable icon = null;
+        switch (mId) {
+            case ID_IME_SWITCH_BUTTON:
+                // TODO: Just showing the first shortcut IME subtype for now. Should handle all
+                // shortcuts as appropriate.
+                icon = getSubtypeIcon(getCurrentInputMethodInfo(),
+                        mImm.getCurrentInputMethodSubtype());
+                break;
+            case ID_IME_SHORTCUT_BUTTON:
+                icon = getShortcutInputMethodAndSubtypeDrawable();
+                break;
+        }
         if (icon == null) {
             mIcon.setImageResource(R.drawable.ic_sysbar_ime_default);
         } else {
@@ -126,7 +182,8 @@
         }
     }
 
-    public void setIMEButtonVisible(boolean visible) {
+    public void setIMEButtonVisible(IBinder token, boolean visible) {
+        mToken = token;
         mKeyboardShown = visible;
         refreshStatusIcon(mKeyboardShown);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index a934cd7..6db5b2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -107,7 +107,8 @@
     View mMenuButton;
     View mRecentButton;
 
-    InputMethodButton mInputMethodButton;
+    InputMethodButton mInputMethodSwitchButton;
+    InputMethodButton mInputMethodShortcutButton;
 
     NotificationPanel mNotificationPanel;
     NotificationPeekPanel mNotificationPeekWindow;
@@ -294,7 +295,8 @@
         mRecentButton.setOnClickListener(mOnClickListener);
 
         // The bar contents buttons
-        mInputMethodButton = (InputMethodButton) sb.findViewById(R.id.imeButton);
+        mInputMethodSwitchButton = (InputMethodButton) sb.findViewById(R.id.imeSwitchButton);
+        mInputMethodShortcutButton = (InputMethodButton) sb.findViewById(R.id.imeShortcutButton);
 
         // "shadows" of the status bar features, for lights-out mode
         mBackShadow = sb.findViewById(R.id.back_shadow);
@@ -645,11 +647,12 @@
         mMenuButton.setVisibility(visible ? View.VISIBLE : View.GONE);
     }
 
-    public void setIMEButtonVisible(boolean visible) {
+    public void setIMEButtonVisible(IBinder token, boolean visible) {
         if (DEBUG) {
             Slog.d(TAG, (visible?"showing":"hiding") + " the IME button");
         }
-        mInputMethodButton.setIMEButtonVisible(visible);
+        mInputMethodSwitchButton.setIMEButtonVisible(token, visible);
+        mInputMethodShortcutButton.setIMEButtonVisible(token, visible);
     }
 
     private void setAreThereNotifications() {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 723432d..c574058 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -964,7 +964,7 @@
             }
 
             synchronized (mMethodMap) {
-                mStatusBar.setIMEButtonVisible(visible);
+                mStatusBar.setIMEButtonVisible(token, visible);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -1007,23 +1007,29 @@
 
         if (id.equals(mCurMethodId)) {
             ArrayList<InputMethodSubtype> subtypes = info.getSubtypes();
+            InputMethodSubtype subtype = null;
             if (subtypeId >= 0 && subtypeId < subtypes.size()) {
-                InputMethodSubtype subtype = subtypes.get(subtypeId);
-                if (subtype != mCurrentSubtype) {
-                    synchronized (mMethodMap) {
-                        if (mCurMethod != null) {
-                            try {
-                                setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
-                                if (mInputShown) {
-                                    // If mInputShown is false, there is no IME button on the
-                                    // system bar.
-                                    // Thus there is no need to make it invisible explicitly.
-                                    mStatusBar.setIMEButtonVisible(true);
-                                }
-                                mCurMethod.changeInputMethodSubtype(subtype);
-                            } catch (RemoteException e) {
-                                return;
+                subtype = subtypes.get(subtypeId);
+            }
+            if (subtype != mCurrentSubtype) {
+                synchronized (mMethodMap) {
+                    if (mCurMethod != null) {
+                        try {
+                            setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
+                            if (mInputShown) {
+                                // If mInputShown is false, there is no IME button on the
+                                // system bar.
+                                // Thus there is no need to make it invisible explicitly.
+                                mStatusBar.setIMEButtonVisible(mCurToken, true);
                             }
+                            // If subtype is null, try to find the most applicable one from
+                            // getCurrentInputMethodSubtype.
+                            if (subtype == null) {
+                                subtype = getCurrentInputMethodSubtype();
+                            }
+                            mCurMethod.changeInputMethodSubtype(subtype);
+                        } catch (RemoteException e) {
+                            return;
                         }
                     }
                 }
@@ -1942,28 +1948,29 @@
      * return defaultSubtypeId
      * @return the most applicable subtypeId
      */
-    private int findLastResortApplicableSubtypeLocked(
+    private InputMethodSubtype findLastResortApplicableSubtypeLocked(
             List<InputMethodSubtype> subtypes, String mode, String locale, int defaultSubtypeId) {
         if (subtypes == null || subtypes.size() == 0) {
-            return NOT_A_SUBTYPE_ID;
+            return null;
         }
         if (TextUtils.isEmpty(locale)) {
             locale = mContext.getResources().getConfiguration().locale.toString();
         }
         final String language = locale.substring(0, 2);
         boolean partialMatchFound = false;
-        int applicableSubtypeId = defaultSubtypeId;
+        InputMethodSubtype applicableSubtype = null;
         for (int i = 0; i < subtypes.size(); ++i) {
-            final String subtypeLocale = subtypes.get(i).getLocale();
+            InputMethodSubtype subtype = subtypes.get(i);
+            final String subtypeLocale = subtype.getLocale();
             // An applicable subtype should match "mode".
             if (subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
                 if (locale.equals(subtypeLocale)) {
                     // Exact match (e.g. system locale is "en_US" and subtype locale is "en_US")
-                    applicableSubtypeId = i;
+                    applicableSubtype = subtype;
                     break;
                 } else if (!partialMatchFound && subtypeLocale.startsWith(language)) {
                     // Partial match (e.g. system locale is "en_US" and subtype locale is "en")
-                    applicableSubtypeId = i;
+                    applicableSubtype = subtype;
                     partialMatchFound = true;
                 }
             }
@@ -1972,10 +1979,10 @@
         // The first subtype applicable to the system locale will be defined as the most applicable
         // subtype.
         if (DEBUG) {
-            Slog.d(TAG, "Applicable InputMethodSubtype was found: " + applicableSubtypeId + ","
-                    + subtypes.get(applicableSubtypeId).getLocale());
+            Slog.d(TAG, "Applicable InputMethodSubtype was found: " + applicableSubtype.getMode()
+                    + "," + applicableSubtype.getLocale());
         }
-        return applicableSubtypeId;
+        return applicableSubtype;
     }
 
     // If there are no selected shortcuts, tries finding the most applicable ones.
@@ -1983,59 +1990,66 @@
             findLastResortApplicableShortcutInputMethodAndSubtypeLocked(String mode) {
         List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
         InputMethodInfo mostApplicableIMI = null;
-        int mostApplicableSubtypeId = NOT_A_SUBTYPE_ID;
+        InputMethodSubtype mostApplicableSubtype = null;
         boolean foundInSystemIME = false;
 
         // Search applicable subtype for each InputMethodInfo
         for (InputMethodInfo imi: imis) {
-            int subtypeId = NOT_A_SUBTYPE_ID;
+            InputMethodSubtype subtype = null;
             if (mCurrentSubtype != null) {
                 // 1. Search with the current subtype's locale and the enabled subtypes
-                subtypeId = findLastResortApplicableSubtypeLocked(
+                subtype = findLastResortApplicableSubtypeLocked(
                         mSettings.getEnabledInputMethodSubtypeListLocked(
                         imi), mode, mCurrentSubtype.getLocale(), NOT_A_SUBTYPE_ID);
-                if (subtypeId == NOT_A_SUBTYPE_ID) {
+                if (subtype == null) {
                     // 2. Search with the current subtype's locale and all subtypes
-                    subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
+                    subtype = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
                             mode, mCurrentSubtype.getLocale(), NOT_A_SUBTYPE_ID);
                 }
             }
             // 3. Search with the system locale and the enabled subtypes
-            if (subtypeId == NOT_A_SUBTYPE_ID) {
-                subtypeId = findLastResortApplicableSubtypeLocked(
+            if (subtype == null) {
+                subtype = findLastResortApplicableSubtypeLocked(
                         mSettings.getEnabledInputMethodSubtypeListLocked(
                         imi), mode, null, NOT_A_SUBTYPE_ID);
             }
-            if (subtypeId == NOT_A_SUBTYPE_ID) {
+            if (subtype == null) {
                 // 4. Search with the system locale and all subtypes
-                subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
+                subtype = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
                         mode, null, NOT_A_SUBTYPE_ID);
             }
-            if (subtypeId != NOT_A_SUBTYPE_ID) {
+            if (subtype != null) {
                 if (imi.getId().equals(mCurMethodId)) {
                     // The current input method is the most applicable IME.
                     mostApplicableIMI = imi;
-                    mostApplicableSubtypeId = subtypeId;
+                    mostApplicableSubtype = subtype;
                     break;
                 } else if ((imi.getServiceInfo().applicationInfo.flags
                         & ApplicationInfo.FLAG_SYSTEM) != 0) {
                     // The system input method is 2nd applicable IME.
                     mostApplicableIMI = imi;
-                    mostApplicableSubtypeId = subtypeId;
+                    mostApplicableSubtype = subtype;
                     foundInSystemIME = true;
                 } else if (!foundInSystemIME) {
                     mostApplicableIMI = imi;
-                    mostApplicableSubtypeId = subtypeId;
+                    mostApplicableSubtype = subtype;
                 }
             }
         }
         if (DEBUG) {
-            Slog.w(TAG, "Most applicable shortcut input method subtype was:"
-                    + mostApplicableIMI.getId() + "," + mostApplicableSubtypeId);
+            if (mostApplicableIMI != null) {
+                Slog.w(TAG, "Most applicable shortcut input method was:"
+                        + mostApplicableIMI.getId());
+                if (mostApplicableSubtype != null) {
+                    Slog.w(TAG, "Most applicable shortcut input method subtype was:"
+                            + "," + mostApplicableSubtype.getMode() + ","
+                            + mostApplicableSubtype.getLocale());
+                }
+            }
         }
-        if (mostApplicableIMI != null && mostApplicableSubtypeId != NOT_A_SUBTYPE_ID) {
+        if (mostApplicableIMI != null) {
             return new Pair<InputMethodInfo, InputMethodSubtype> (mostApplicableIMI,
-                    mostApplicableIMI.getSubtypes().get(mostApplicableSubtypeId));
+                    mostApplicableSubtype);
         } else {
             return null;
         }
@@ -2063,15 +2077,12 @@
                         // the most applicable subtype from all subtypes whose mode is
                         // SUBTYPE_MODE_KEYBOARD. This is an exceptional case, so we will hardcode
                         // the mode.
-                        subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
+                        mCurrentSubtype = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
                                 SUBTYPE_MODE_KEYBOARD, null, DEFAULT_SUBTYPE_ID);
                     }
-                }
-                if (subtypeId != NOT_A_SUBTYPE_ID) {
+                } else {
                     mCurrentSubtype =
                             mMethodMap.get(lastInputMethodId).getSubtypes().get(subtypeId);
-                } else {
-                    mCurrentSubtype = null;
                 }
             }
             return mCurrentSubtype;
@@ -2101,7 +2112,7 @@
                             SUBTYPE_MODE_VOICE);
                 addShortcutInputMethodAndSubtypes(info.first, info.second);
             }
-            ArrayList ret = new ArrayList<Object>();
+            ArrayList<Object> ret = new ArrayList<Object>();
             for (InputMethodInfo imi: mShortcutInputMethodsAndSubtypes.keySet()) {
                 ret.add(imi);
                 for (InputMethodSubtype subtype: mShortcutInputMethodsAndSubtypes.get(imi)) {
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 596db57..cbfa4ee 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -73,6 +73,7 @@
     boolean mLightsOn = true;
     boolean mMenuVisible = false;
     boolean mIMEButtonVisible = false;
+    IBinder mIMEToken = null;
 
     private class DisableRecord implements IBinder.DeathRecipient {
         String pkg;
@@ -257,7 +258,7 @@
         }
     }
 
-    public void setIMEButtonVisible(final boolean visible) {
+    public void setIMEButtonVisible(final IBinder token, final boolean visible) {
         enforceStatusBar();
 
         if (SPEW) Slog.d(TAG, (visible?"showing":"hiding") + " IME Button");
@@ -267,11 +268,12 @@
             // mIMEButtonVisible because mIMEButtonVisible may not have been set to false when the
             // previous IME was destroyed.
             mIMEButtonVisible = visible;
+            mIMEToken = token;
             mHandler.post(new Runnable() {
                 public void run() {
                     if (mBar != null) {
                         try {
-                            mBar.setIMEButtonVisible(visible);
+                            mBar.setIMEButtonVisible(token, visible);
                         } catch (RemoteException ex) {
                         }
                     }
@@ -351,7 +353,7 @@
     // ================================================================================
     public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
             List<IBinder> notificationKeys, List<StatusBarNotification> notifications,
-            int switches[]) {
+            int switches[], List<IBinder> binders) {
         enforceStatusBarService();
 
         Slog.i(TAG, "registerStatusBar bar=" + bar);
@@ -370,6 +372,7 @@
             switches[1] = mLightsOn ? 1 : 0;
             switches[2] = mMenuVisible ? 1 : 0;
             switches[3] = mIMEButtonVisible ? 1 : 0;
+            binders.add(mIMEToken);
         }
     }