OSDN Git Service

Handle BadTokenException exception more reliably.
authorYohei Yukawa <yukawa@google.com>
Mon, 14 Sep 2015 23:48:15 +0000 (16:48 -0700)
committerYohei Yukawa <yukawa@google.com>
Mon, 14 Sep 2015 23:48:15 +0000 (16:48 -0700)
This is a follow up for I2c21573cf972145ab08e66604cdb9344139a3f31, which
added BadTokenException handler so that we can deal with unavoidable
runtime exceptions. However, it turns out that CL does not work well
in a certain case.

One problem in I2c21573cf972145ab08e66604cdb9344139a3f31 that it added
the exception handler in the call site of
InputMethodService#showWindow(boolean) rather than callee side as
follows.

    try {
        showWindow(true);
    } catch (BadTokenException e) {
        if (DEBUG) Log.v(TAG, "BadTokenException: IME is done.");
        mWindowVisible = false;
    }

However, the above code fails to update #mWindowVisible if an IME
overrides InputMethodService#showWindow(boolean) but catch-and-ignore
BadTokenException as follows.

    @Override
    public void showWindow(boolean showInput) {
        try {
            super.showWindow(showInput);
            // Do something if super.showWindow() succeeds.
        } catch (BadTokenException ex) {
            // Do something if super.showWindow() fails.
        }
    }

With this CL, InputMethodService#mWindowVisible is always updated in
the callee side whenever it should be.

Note that this CL does not change anything about which method can
throw BadTokenException and which method catch-and-ignores it so as
not to break existing IMEs unexpectedly.

Bug: 23798142
Change-Id: Id1e5f236f48c8ef01b7f157ba3f6e7ab2c26b135

core/java/android/inputmethodservice/InputMethodService.java

index 6e28982..8ab8991 100644 (file)
@@ -436,9 +436,12 @@ public class InputMethodService extends AbstractInputMethodService {
                 try {
                     showWindow(true);
                 } catch (BadTokenException e) {
-                    if (DEBUG) Log.v(TAG, "BadTokenException: IME is done.");
-                    mWindowVisible = false;
-                    mWindowAdded = false;
+                    // We have ignored BadTokenException here since Jelly Bean MR-2 (API Level 18).
+                    // We could ignore BadTokenException in InputMethodService#showWindow() instead,
+                    // but it may break assumptions for those who override #showWindow() that we can
+                    // detect errors in #showWindow() by checking BadTokenException.
+                    // TODO: Investigate its feasibility.  Update JavaDoc of #showWindow() of
+                    // whether it's OK to override #showWindow() or not.
                 }
             }
             clearInsetOfPreviousIme();
@@ -1445,7 +1448,19 @@ public class InputMethodService extends AbstractInputMethodService {
             mWindowWasVisible = mWindowVisible;
             mInShowWindow = true;
             showWindowInner(showInput);
+        } catch (BadTokenException e) {
+            // BadTokenException is a normal consequence in certain situations, e.g., swapping IMEs
+            // while there is a DO_SHOW_SOFT_INPUT message in the IIMethodWrapper queue.
+            if (DEBUG) Log.v(TAG, "BadTokenException: IME is done.");
+            mWindowVisible = false;
+            mWindowAdded = false;
+            // Rethrow the exception to preserve the existing behavior.  Some IMEs may have directly
+            // called this method and relied on this exception for some clean-up tasks.
+            // TODO: Give developers a clear guideline of whether it's OK to call this method or
+            // InputMethodManager#showSoftInputFromInputMethod() should always be used instead.
+            throw e;
         } finally {
+            // TODO: Is it OK to set true when we get BadTokenException?
             mWindowWasVisible = true;
             mInShowWindow = false;
         }