Catch BadTokenException and continue.

BadTokenException is a normal consequence of swapping IMEs while there
is a DO_SHOW_SOFT_INPUT message in the IIMethodWrapper queue. This
race condition cannot be avoided without an unacceptable lock down of
InputMethodManagerService.

Fixes bug 8387663.
Fixes bug 8263462.

Change-Id: I2c21573cf972145ab08e66604cdb9344139a3f31
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index d59c7b8..1128230 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -54,7 +54,7 @@
         implements HandlerCaller.Callback {
     private static final String TAG = "InputMethodWrapper";
     private static final boolean DEBUG = false;
-    
+
     private static final int DO_DUMP = 1;
     private static final int DO_ATTACH_TOKEN = 10;
     private static final int DO_SET_INPUT_CONTEXT = 20;
@@ -284,12 +284,6 @@
                 flags, resultReceiver));
     }
 
-    @Override
-    public void removeSoftInputMessages() {
-        mCaller.removeMessages(DO_SHOW_SOFT_INPUT);
-        mCaller.removeMessages(DO_HIDE_SOFT_INPUT);
-    }
-
     public void changeInputMethodSubtype(InputMethodSubtype subtype) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CHANGE_INPUTMETHOD_SUBTYPE,
                 subtype));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 288ceff..5a9cde1 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -39,7 +39,6 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
-import android.util.Slog;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -49,6 +48,7 @@
 import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowManager;
+import android.view.WindowManager.BadTokenException;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.EditorInfo;
@@ -352,7 +352,6 @@
          * Take care of attaching the given window token provided by the system.
          */
         public void attachToken(IBinder token) {
-            Slog.i(TAG, "attachToken: Existing token=" + mToken + " new token=" + token);
             if (mToken == null) {
                 mToken = token;
                 mWindow.setToken(token);
@@ -419,11 +418,16 @@
          * Handle a request by the system to show the soft input area.
          */
         public void showSoftInput(int flags, ResultReceiver resultReceiver) {
-            if (true || DEBUG) Slog.v(TAG, "showSoftInput()");
+            if (DEBUG) Log.v(TAG, "showSoftInput()");
             boolean wasVis = isInputViewShown();
             mShowInputFlags = 0;
             if (onShowInputRequested(flags, false)) {
-                showWindow(true);
+                try {
+                    showWindow(true);
+                } catch (BadTokenException e) {
+                    if (DEBUG) Log.v(TAG, "BadTokenException: IME is done.");
+                    mWindowVisible = false;
+                }
             }
             // If user uses hard keyboard, IME button should always be shown.
             boolean showing = onEvaluateInputViewShown();
@@ -1390,7 +1394,7 @@
     }
     
     public void showWindow(boolean showInput) {
-        if (true || DEBUG) Slog.v(TAG, "Showing window: showInput=" + showInput
+        if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
                 + " mShowInputRequested=" + mShowInputRequested
                 + " mWindowAdded=" + mWindowAdded
                 + " mWindowCreated=" + mWindowCreated
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index c2a7fc7..5db860b 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -33,28 +33,26 @@
  * Service).
  * {@hide}
  */
-interface IInputMethod {
-    oneway void attachToken(IBinder token);
-    
-    oneway void bindInput(in InputBinding binding);
-    
-    oneway void unbindInput();
+oneway interface IInputMethod {
+    void attachToken(IBinder token);
 
-    oneway void startInput(in IInputContext inputContext, in EditorInfo attribute);
+    void bindInput(in InputBinding binding);
 
-    oneway void restartInput(in IInputContext inputContext, in EditorInfo attribute);
+    void unbindInput();
 
-    oneway void createSession(IInputMethodCallback callback);
-    
-    oneway void setSessionEnabled(IInputMethodSession session, boolean enabled);
-    
-    oneway void revokeSession(IInputMethodSession session);
-    
-    oneway void showSoftInput(int flags, in ResultReceiver resultReceiver);
-    
-    oneway void hideSoftInput(int flags, in ResultReceiver resultReceiver);
+    void startInput(in IInputContext inputContext, in EditorInfo attribute);
 
-    void removeSoftInputMessages();
+    void restartInput(in IInputContext inputContext, in EditorInfo attribute);
 
-    oneway void changeInputMethodSubtype(in InputMethodSubtype subtype);
+    void createSession(IInputMethodCallback callback);
+
+    void setSessionEnabled(IInputMethodSession session, boolean enabled);
+
+    void revokeSession(IInputMethodSession session);
+
+    void showSoftInput(int flags, in ResultReceiver resultReceiver);
+
+    void hideSoftInput(int flags, in ResultReceiver resultReceiver);
+
+    void changeInputMethodSubtype(in InputMethodSubtype subtype);
 }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 14841af..f6c9d82 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1237,24 +1237,13 @@
     public void onServiceConnected(ComponentName name, IBinder service) {
         synchronized (mMethodMap) {
             if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
-                IInputMethod prevMethod = mCurMethod;
                 mCurMethod = IInputMethod.Stub.asInterface(service);
                 if (mCurToken == null) {
                     Slog.w(TAG, "Service connected without a token!");
                     unbindCurrentMethodLocked(false, false);
                     return;
                 }
-                // Remove messages relating to the previous service. Otherwise WindowManagerService
-                // will throw a BadTokenException because the old token is being removed.
-                if (prevMethod != null) {
-                    try {
-                        prevMethod.removeSoftInputMessages();
-                    } catch (RemoteException e) {
-                    }
-                }
-                mCaller.removeMessages(MSG_SHOW_SOFT_INPUT);
-                mCaller.removeMessages(MSG_HIDE_SOFT_INPUT);
-                if (true || DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
+                if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
                 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
                         MSG_ATTACH_TOKEN, mCurMethod, mCurToken));
                 if (mCurClient != null) {
@@ -1700,7 +1689,7 @@
                     }
                 }
 
-                if (true || DEBUG) Slog.v(TAG, "Client requesting input be shown");
+                if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
                 return showCurrentInputLocked(flags, resultReceiver);
             }
         } finally {
@@ -1724,8 +1713,7 @@
 
         boolean res = false;
         if (mCurMethod != null) {
-            if (true ||DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken,
-                    new RuntimeException("here").fillInStackTrace());
+            if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
             executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
                     MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
                     resultReceiver));
@@ -1797,13 +1785,11 @@
     boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
         if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
                 && (mShowExplicitlyRequested || mShowForced)) {
-            if (true ||DEBUG) Slog.v(TAG,
-                    "Not hiding: explicit show not cancelled by non-explicit hide");
+            if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
             return false;
         }
         if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
-            if (true ||DEBUG) Slog.v(TAG,
-                    "Not hiding: forced show not cancelled by not-always hide");
+            if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
             return false;
         }
         boolean res;
@@ -2314,7 +2300,7 @@
             case MSG_SHOW_SOFT_INPUT:
                 args = (SomeArgs)msg.obj;
                 try {
-                    if (true || DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
+                    if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
                             + msg.arg1 + ", " + args.arg2 + ")");
                     ((IInputMethod)args.arg1).showSoftInput(msg.arg1, (ResultReceiver)args.arg2);
                 } catch (RemoteException e) {
@@ -2324,7 +2310,7 @@
             case MSG_HIDE_SOFT_INPUT:
                 args = (SomeArgs)msg.obj;
                 try {
-                    if (true || DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
+                    if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
                             + args.arg2 + ")");
                     ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
                 } catch (RemoteException e) {
@@ -2334,7 +2320,7 @@
             case MSG_ATTACH_TOKEN:
                 args = (SomeArgs)msg.obj;
                 try {
-                    if (true || DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);
+                    if (DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);
                     ((IInputMethod)args.arg1).attachToken((IBinder)args.arg2);
                 } catch (RemoteException e) {
                 }