OSDN Git Service

Clear the inset of previous IME when necessary.
authorYohei Yukawa <yukawa@google.com>
Thu, 28 May 2015 01:54:18 +0000 (18:54 -0700)
committerYohei Yukawa <yukawa@google.com>
Thu, 28 May 2015 22:52:49 +0000 (22:52 +0000)
In the following scenario, the system continues keeping the previous
IME's inset in the display until the new IME shows its window.
1. an IME shows its software keyboard with reporting non-empty inset.
2. the user switches to another IME, which does not show the software
   keyboard when it is selected (e.g., because the physical keyboard
   is connected.)

This CL tries to address above situation by introducing a new state
flag IMMS#mShouldClearInsetOfPreviousIme to clear the previous IME's
inset when necessary.

Bug: 15922840
Change-Id: Ib04967f39b2529251e4835c42e9f99dba2cf43f2

core/java/android/inputmethodservice/InputMethodService.java

index 1b57055..81a65f8 100644 (file)
@@ -306,6 +306,14 @@ public class InputMethodService extends AbstractInputMethodService {
     int mStatusIcon;
     int mBackDisposition;
 
+    /**
+     * {@code true} when the previous IME had non-empty inset at the bottom of the screen and we
+     * have not shown our own window yet.  In this situation, the previous inset continues to be
+     * shown as an empty region until it is explicitly updated. Basically we can trigger the update
+     * by calling 1) {@code mWindow.show()} or 2) {@link #clearInsetOfPreviousIme()}.
+     */
+    boolean mShouldClearInsetOfPreviousIme;
+
     final Insets mTmpInsets = new Insets();
     final int[] mTmpLocation = new int[2];
 
@@ -408,6 +416,7 @@ public class InputMethodService extends AbstractInputMethodService {
             mShowInputRequested = false;
             mShowInputForced = false;
             doHideWindow();
+            clearInsetOfPreviousIme();
             if (resultReceiver != null) {
                 resultReceiver.send(wasVis != isInputViewShown()
                         ? InputMethodManager.RESULT_HIDDEN
@@ -432,6 +441,7 @@ public class InputMethodService extends AbstractInputMethodService {
                     mWindowAdded = false;
                 }
             }
+            clearInsetOfPreviousIme();
             // If user uses hard keyboard, IME button should always be shown.
             boolean showing = isInputViewShown();
             mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
@@ -669,6 +679,9 @@ public class InputMethodService extends AbstractInputMethodService {
         super.setTheme(mTheme);
         super.onCreate();
         mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
+        // If the previous IME has occupied non-empty inset in the screen, we need to decide whether
+        // we continue to use the same size of the inset or update it
+        mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
@@ -1494,6 +1507,9 @@ public class InputMethodService extends AbstractInputMethodService {
             if (DEBUG) Log.v(TAG, "showWindow: showing!");
             onWindowShown();
             mWindow.show();
+            // Put here rather than in onWindowShown() in case people forget to call
+            // super.onWindowShown().
+            mShouldClearInsetOfPreviousIme = false;
         }
     }
 
@@ -1540,7 +1556,23 @@ public class InputMethodService extends AbstractInputMethodService {
     public void onWindowHidden() {
         // Intentionally empty
     }
-    
+
+    /**
+     * Reset the inset occupied the previous IME when and only when
+     * {@link #mShouldClearInsetOfPreviousIme} is {@code true}.
+     */
+    private void clearInsetOfPreviousIme() {
+        if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme() "
+                + " mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
+        if (!mShouldClearInsetOfPreviousIme || mWindow == null) return;
+        // We do not call onWindowShown() and onWindowHidden() so as not to make the IME author
+        // confused.
+        // TODO: Find out a better way which has less side-effect.
+        mWindow.show();
+        mWindow.hide();
+        mShouldClearInsetOfPreviousIme = false;
+    }
+
     /**
      * Called when a new client has bound to the input method.  This
      * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
@@ -2428,5 +2460,6 @@ public class InputMethodService extends AbstractInputMethodService {
                 + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
                 + " touchableInsets=" + mTmpInsets.touchableInsets
                 + " touchableRegion=" + mTmpInsets.touchableRegion);
+        p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
     }
 }