From 833bdcedceee60a873694a77587393abfc830eb5 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Sun, 15 May 2016 20:05:56 -0700 Subject: [PATCH] Make IMS#clearInsetOfPreviousIme() reliable. This is a follow-up to my previous CL [1] for Bug 15922840 so that we can clear the following variables in a more reliable way. - PhoneWindowManager#mLastInputMethodWindow - PhoneWindowManager#mLastInputMethodTargetWindow The idea behind CL [2] is that when InputMethodManagerService (IMMS) is switching from an IME to another IME, IMMS can send a signal to WindowManagerService (WMS) to remember the current IME's inset so that the system can continue using it to reduce jank until the new inset is specified by the next IME. As summarized in Bug 28781358, however, if the next IME does not show the window after the IME switch, WMS (or PhoneWindowManager to be precise) keeps using the previous IME's inset unexpectedly until the new IME shows its window. All we have seen in Bug 15922840 and Bug 26663589 fall into this category. The idea of this CL is just adding a hidden API to InputMethodManager so that InputMethodService#clearInsetOfPreviousIme() can surely terminate the IME transition state managed in PhoneWindowManager, rather than relying on a hack of calling SoftInputWindow#show() and SoftInputWindow#hide(), which actually does not work for Bug 26663589. [1]: Ib04967f39b2529251e4835c42e9f99dba2cf43f2 2977eb7b6ce82309a1bb1ba4ab698f503cb0388a [2]: I5723f627ce323b0d12bd7b93f5b35fc4d342b50c 792faa2c16d319e874a1d633f964a78266d5f3f2 Note that addressing all the corner cases in [2] still requires lots of non-trivial change. Hence this CL focuses only on Bug 26663589 (and the case we handled in Bug 15922840). Bug: 26663589 Change-Id: Ib567daa009c1139858dccadcfc6a04465ebecf36 --- .../InputMethodService.java | 15 +++---------- .../android/view/WindowManagerInternal.java | 7 ++++++ .../view/inputmethod/InputMethodManager.java | 22 +++++++++++++++++++ .../internal/view/IInputMethodManager.aidl | 2 ++ .../server/InputMethodManagerService.java | 21 ++++++++++++++++++ .../server/wm/WindowManagerService.java | 7 ++++++ .../android/BridgeIInputMethodManager.java | 5 +++++ 7 files changed, 67 insertions(+), 12 deletions(-) diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 923be5e06582b..4799773d9ed69 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1714,18 +1714,9 @@ public class InputMethodService extends AbstractInputMethodService { private void clearInsetOfPreviousIme() { if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme() " + " mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme); - if (!mShouldClearInsetOfPreviousIme || mWindow == null) return; - try { - // 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(); - } catch (WindowManager.BadTokenException e) { - if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme: BadTokenException: IME is done."); - mWindowVisible = false; - mWindowAdded = false; - } + if (!mShouldClearInsetOfPreviousIme) return; + + mImm.clearLastInputMethodWindowForTransition(mToken); mShouldClearInsetOfPreviousIme = false; } diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java index 4b188c4e35c1b..610dff8c8bab6 100644 --- a/core/java/android/view/WindowManagerInternal.java +++ b/core/java/android/view/WindowManagerInternal.java @@ -260,6 +260,13 @@ public abstract class WindowManagerInternal { */ public abstract void saveLastInputMethodWindowForTransition(); + /** + * Clears last input method window for transition. + * + * Note that it is assumed that this method is called only by InputMethodManagerService. + */ + public abstract void clearLastInputMethodWindowForTransition(); + /** * Returns true when the hardware keyboard is available. */ diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 5a9a212538b68..1618758929ef1 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -2139,6 +2139,28 @@ public final class InputMethodManager { } } + /** + * Tells the system that the IME decided to not show a window and the system no longer needs to + * use the previous IME's inset. + * + *

Caveat: {@link android.inputmethodservice.InputMethodService#clearInsetOfPreviousIme()} + * is the only expected caller of this method. Do not depend on this anywhere else.

+ * + *

TODO: We probably need to reconsider how IME should be handled.

+ * @hide + * @param token Supplies the identifying token given to an input method when it was started, + * which allows it to perform this operation on itself. + */ + public void clearLastInputMethodWindowForTransition(final IBinder token) { + synchronized (mH) { + try { + mService.clearLastInputMethodWindowForTransition(token); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + /** * Force switch to the last used input method and subtype. If the last input method didn't have * any subtypes, the framework will simply switch to the last input method with no subtype diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 94c94c190e6b8..cb7c3bfecc89b 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -79,5 +79,7 @@ interface IInputMethodManager { boolean setInputMethodEnabled(String id, boolean enabled); void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes); int getInputMethodWindowVisibleHeight(); + void clearLastInputMethodWindowForTransition(in IBinder token); + oneway void notifyUserAction(int sequenceNumber); } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index a584f707f9a9d..b0a00e654b804 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -2642,6 +2642,27 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mWindowManagerInternal.getInputMethodWindowVisibleHeight(); } + @Override + public void clearLastInputMethodWindowForTransition(IBinder token) { + if (!calledFromValidUser()) { + return; + } + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mMethodMap) { + if (!calledWithValidToken(token)) { + final int uid = Binder.getCallingUid(); + Slog.e(TAG, "Ignoring clearLastInputMethodWindowForTransition due to an " + + "invalid token. uid:" + uid + " token:" + token); + return; + } + } + mWindowManagerInternal.clearLastInputMethodWindowForTransition(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + @Override public void notifyUserAction(int sequenceNumber) { if (DEBUG) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 11327582a481d..239cc8eaae8cd 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -11293,6 +11293,13 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void clearLastInputMethodWindowForTransition() { + synchronized (mWindowMap) { + mPolicy.setLastInputMethodWindowLw(null, null); + } + } + @Override public boolean isHardKeyboardAvailable() { synchronized (mWindowMap) { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java index 0cf51a46f63f4..3f276c9375ba6 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java @@ -218,6 +218,11 @@ public class BridgeIInputMethodManager implements IInputMethodManager { } + @Override + public void clearLastInputMethodWindowForTransition(IBinder arg0) throws RemoteException { + // TODO Auto-generated method stub + } + @Override public InputBindResult startInputOrWindowGainedFocus( /* @InputMethodClient.StartInputReason */ int startInputReason,