Loading core/java/android/inputmethodservice/IInputMethodWrapper.java +8 −5 Original line number Diff line number Diff line Loading @@ -166,8 +166,9 @@ class IInputMethodWrapper extends IInputMethod.Stub final SomeArgs args = (SomeArgs) msg.obj; final int missingMethods = msg.arg1; final boolean restarting = msg.arg2 != 0; final IInputContext inputContext = (IInputContext) args.arg1; final EditorInfo info = (EditorInfo) args.arg2; final IBinder startInputToken = (IBinder) args.arg1; final IInputContext inputContext = (IInputContext) args.arg2; final EditorInfo info = (EditorInfo) args.arg3; final InputConnection ic = inputContext != null ? new InputConnectionWrapper(mTarget, inputContext, missingMethods) : null; info.makeCompatible(mTargetSdkVersion); Loading @@ -176,6 +177,8 @@ class IInputMethodWrapper extends IInputMethod.Stub } else { inputMethod.startInput(ic, info); } inputMethod.dispatchStartInputWithToken(ic, info, true /* initial */, startInputToken); args.recycle(); return; } Loading Loading @@ -255,11 +258,11 @@ class IInputMethodWrapper extends IInputMethod.Stub } @Override public void startInput(IInputContext inputContext, public void startInput(IBinder startInputToken, IInputContext inputContext, @InputConnectionInspector.MissingMethodFlags final int missingMethods, EditorInfo attribute, boolean restarting) { mCaller.executeOrSendMessage(mCaller.obtainMessageIIOO(DO_START_INPUT, missingMethods, restarting ? 1 : 0, inputContext, attribute)); mCaller.executeOrSendMessage(mCaller.obtainMessageIIOOO(DO_START_INPUT, missingMethods, restarting ? 1 : 0, startInputToken, inputContext, attribute)); } @Override Loading core/java/android/inputmethodservice/InputMethodService.java +41 −8 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.Dialog; import android.content.Context; Loading Loading @@ -292,6 +293,19 @@ public class InputMethodService extends AbstractInputMethodService { InputConnection mStartedInputConnection; EditorInfo mInputEditorInfo; /** * A token to keep tracking the last IPC that triggered * {@link #doStartInput(InputConnection, EditorInfo, boolean)}. If * {@link #doStartInput(InputConnection, EditorInfo, boolean)} was not caused by IPCs from * {@link com.android.server.InputMethodManagerService}, this needs to remain unchanged. * * <p>Some IPCs to {@link com.android.server.InputMethodManagerService} require this token to * disentangle event flows for various purposes such as better window animation and providing * fine-grained debugging information.</p> */ @Nullable private IBinder mStartInputToken; int mShowInputFlags; boolean mShowInputRequested; boolean mLastShowInputRequested; Loading Loading @@ -415,6 +429,23 @@ public class InputMethodService extends AbstractInputMethodService { doStartInput(ic, attribute, true); } /** * {@inheritDoc} * @hide */ @Override public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo, boolean restarting, @NonNull IBinder startInputToken) { mStartInputToken = startInputToken; // This needs to be dispatched to interface methods rather than doStartInput(). // Otherwise IME developers who have overridden those interface methods will lose // notifications. super.dispatchStartInputWithToken(inputConnection, editorInfo, restarting, startInputToken); } /** * Handle a request by the system to hide the soft input area. */ Loading Loading @@ -454,8 +485,8 @@ public class InputMethodService extends AbstractInputMethodService { clearInsetOfPreviousIme(); // If user uses hard keyboard, IME button should always be shown. boolean showing = isInputViewShown(); mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); mImm.setImeWindowStatus(mToken, mStartInputToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); if (resultReceiver != null) { resultReceiver.send(wasVis != isInputViewShown() ? InputMethodManager.RESULT_SHOWN Loading Loading @@ -926,8 +957,8 @@ public class InputMethodService extends AbstractInputMethodService { } // If user uses hard keyboard, IME button should always be shown. boolean showing = onEvaluateInputViewShown(); mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); mImm.setImeWindowStatus(mToken, mStartInputToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); } } Loading Loading @@ -1653,7 +1684,8 @@ public class InputMethodService extends AbstractInputMethodService { final int nextImeWindowStatus = IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0); if (previousImeWindowStatus != nextImeWindowStatus) { mImm.setImeWindowStatus(mToken, nextImeWindowStatus, mBackDisposition); mImm.setImeWindowStatus(mToken, mStartInputToken, nextImeWindowStatus, mBackDisposition); } if ((previousImeWindowStatus & IME_ACTIVE) == 0) { if (DEBUG) Log.v(TAG, "showWindow: showing!"); Loading @@ -1678,7 +1710,7 @@ public class InputMethodService extends AbstractInputMethodService { } private void doHideWindow() { mImm.setImeWindowStatus(mToken, 0, mBackDisposition); mImm.setImeWindowStatus(mToken, mStartInputToken, 0, mBackDisposition); hideWindow(); } Loading Loading @@ -2643,6 +2675,7 @@ public class InputMethodService extends AbstractInputMethodService { p.println(" mInputStarted=" + mInputStarted + " mInputViewStarted=" + mInputViewStarted + " mCandidatesViewStarted=" + mCandidatesViewStarted); p.println(" mStartInputToken=" + mStartInputToken); if (mInputEditorInfo != null) { p.println(" mInputEditorInfo:"); Loading core/java/android/view/inputmethod/InputMethod.java +40 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.inputmethodservice.InputMethodService; Loading Loading @@ -147,6 +149,44 @@ public interface InputMethod { */ public void restartInput(InputConnection inputConnection, EditorInfo attribute); /** * This method is called when {@code {@link #startInput(InputConnection, EditorInfo)} or * {@code {@link #restartInput(InputConnection, EditorInfo)} needs to be dispatched. * * <p>Note: This method is hidden because the {@code startInputToken} that this method is * dealing with is one of internal details, which should not be exposed to the IME developers. * If you override this method, you are responsible for not breaking existing IMEs that expect * {@link #startInput(InputConnection, EditorInfo)} to be still called back.</p> * * @param inputConnection optional specific input connection for communicating with the text * box; if {@code null}, you should use the generic bound input * connection * @param editorInfo information about the text box (typically, an EditText) that requests input * @param restarting {@code false} if this corresponds to * {@link #startInput(InputConnection, EditorInfo)}. Otherwise this * corresponds to {@link #restartInput(InputConnection, EditorInfo)}. * @param startInputToken a token that identifies a logical session that starts with this method * call. Some internal IPCs such as {@link * InputMethodManager#setImeWindowStatus(IBinder, IBinder, int, int)} * require this token to work, and you have to keep the token alive until * the next {@link #startInput(InputConnection, EditorInfo, IBinder)} as * long as your implementation of {@link InputMethod} relies on such * IPCs * @see #startInput(InputConnection, EditorInfo) * @see #restartInput(InputConnection, EditorInfo) * @see EditorInfo * @hide */ default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo, boolean restarting, @NonNull IBinder startInputToken) { if (restarting) { restartInput(inputConnection, editorInfo); } else { startInput(inputConnection, editorInfo); } } /** * Create a new {@link InputMethodSession} that can be handed to client * applications for interacting with the input method. You can later Loading core/java/android/view/inputmethod/InputMethodManager.java +3 −2 Original line number Diff line number Diff line Loading @@ -739,9 +739,10 @@ public final class InputMethodManager { } /** @hide */ public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) { public void setImeWindowStatus(IBinder imeToken, IBinder startInputToken, int vis, int backDisposition) { try { mService.setImeWindowStatus(imeToken, vis, backDisposition); mService.setImeWindowStatus(imeToken, startInputToken, vis, backDisposition); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading core/java/com/android/internal/os/HandlerCaller.java +10 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,16 @@ public class HandlerCaller { return mH.obtainMessage(what, arg1, arg2, args); } public Message obtainMessageIIOOOO(int what, int arg1, int arg2, Object arg3, Object arg4, Object arg5, Object arg6) { SomeArgs args = SomeArgs.obtain(); args.arg1 = arg3; args.arg2 = arg4; args.arg3 = arg5; args.arg4 = arg6; return mH.obtainMessage(what, arg1, arg2, args); } public Message obtainMessageOO(int what, Object arg1, Object arg2) { SomeArgs args = SomeArgs.obtain(); args.arg1 = arg1; Loading Loading
core/java/android/inputmethodservice/IInputMethodWrapper.java +8 −5 Original line number Diff line number Diff line Loading @@ -166,8 +166,9 @@ class IInputMethodWrapper extends IInputMethod.Stub final SomeArgs args = (SomeArgs) msg.obj; final int missingMethods = msg.arg1; final boolean restarting = msg.arg2 != 0; final IInputContext inputContext = (IInputContext) args.arg1; final EditorInfo info = (EditorInfo) args.arg2; final IBinder startInputToken = (IBinder) args.arg1; final IInputContext inputContext = (IInputContext) args.arg2; final EditorInfo info = (EditorInfo) args.arg3; final InputConnection ic = inputContext != null ? new InputConnectionWrapper(mTarget, inputContext, missingMethods) : null; info.makeCompatible(mTargetSdkVersion); Loading @@ -176,6 +177,8 @@ class IInputMethodWrapper extends IInputMethod.Stub } else { inputMethod.startInput(ic, info); } inputMethod.dispatchStartInputWithToken(ic, info, true /* initial */, startInputToken); args.recycle(); return; } Loading Loading @@ -255,11 +258,11 @@ class IInputMethodWrapper extends IInputMethod.Stub } @Override public void startInput(IInputContext inputContext, public void startInput(IBinder startInputToken, IInputContext inputContext, @InputConnectionInspector.MissingMethodFlags final int missingMethods, EditorInfo attribute, boolean restarting) { mCaller.executeOrSendMessage(mCaller.obtainMessageIIOO(DO_START_INPUT, missingMethods, restarting ? 1 : 0, inputContext, attribute)); mCaller.executeOrSendMessage(mCaller.obtainMessageIIOOO(DO_START_INPUT, missingMethods, restarting ? 1 : 0, startInputToken, inputContext, attribute)); } @Override Loading
core/java/android/inputmethodservice/InputMethodService.java +41 −8 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.Dialog; import android.content.Context; Loading Loading @@ -292,6 +293,19 @@ public class InputMethodService extends AbstractInputMethodService { InputConnection mStartedInputConnection; EditorInfo mInputEditorInfo; /** * A token to keep tracking the last IPC that triggered * {@link #doStartInput(InputConnection, EditorInfo, boolean)}. If * {@link #doStartInput(InputConnection, EditorInfo, boolean)} was not caused by IPCs from * {@link com.android.server.InputMethodManagerService}, this needs to remain unchanged. * * <p>Some IPCs to {@link com.android.server.InputMethodManagerService} require this token to * disentangle event flows for various purposes such as better window animation and providing * fine-grained debugging information.</p> */ @Nullable private IBinder mStartInputToken; int mShowInputFlags; boolean mShowInputRequested; boolean mLastShowInputRequested; Loading Loading @@ -415,6 +429,23 @@ public class InputMethodService extends AbstractInputMethodService { doStartInput(ic, attribute, true); } /** * {@inheritDoc} * @hide */ @Override public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo, boolean restarting, @NonNull IBinder startInputToken) { mStartInputToken = startInputToken; // This needs to be dispatched to interface methods rather than doStartInput(). // Otherwise IME developers who have overridden those interface methods will lose // notifications. super.dispatchStartInputWithToken(inputConnection, editorInfo, restarting, startInputToken); } /** * Handle a request by the system to hide the soft input area. */ Loading Loading @@ -454,8 +485,8 @@ public class InputMethodService extends AbstractInputMethodService { clearInsetOfPreviousIme(); // If user uses hard keyboard, IME button should always be shown. boolean showing = isInputViewShown(); mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); mImm.setImeWindowStatus(mToken, mStartInputToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); if (resultReceiver != null) { resultReceiver.send(wasVis != isInputViewShown() ? InputMethodManager.RESULT_SHOWN Loading Loading @@ -926,8 +957,8 @@ public class InputMethodService extends AbstractInputMethodService { } // If user uses hard keyboard, IME button should always be shown. boolean showing = onEvaluateInputViewShown(); mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); mImm.setImeWindowStatus(mToken, mStartInputToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); } } Loading Loading @@ -1653,7 +1684,8 @@ public class InputMethodService extends AbstractInputMethodService { final int nextImeWindowStatus = IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0); if (previousImeWindowStatus != nextImeWindowStatus) { mImm.setImeWindowStatus(mToken, nextImeWindowStatus, mBackDisposition); mImm.setImeWindowStatus(mToken, mStartInputToken, nextImeWindowStatus, mBackDisposition); } if ((previousImeWindowStatus & IME_ACTIVE) == 0) { if (DEBUG) Log.v(TAG, "showWindow: showing!"); Loading @@ -1678,7 +1710,7 @@ public class InputMethodService extends AbstractInputMethodService { } private void doHideWindow() { mImm.setImeWindowStatus(mToken, 0, mBackDisposition); mImm.setImeWindowStatus(mToken, mStartInputToken, 0, mBackDisposition); hideWindow(); } Loading Loading @@ -2643,6 +2675,7 @@ public class InputMethodService extends AbstractInputMethodService { p.println(" mInputStarted=" + mInputStarted + " mInputViewStarted=" + mInputViewStarted + " mCandidatesViewStarted=" + mCandidatesViewStarted); p.println(" mStartInputToken=" + mStartInputToken); if (mInputEditorInfo != null) { p.println(" mInputEditorInfo:"); Loading
core/java/android/view/inputmethod/InputMethod.java +40 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.inputmethodservice.InputMethodService; Loading Loading @@ -147,6 +149,44 @@ public interface InputMethod { */ public void restartInput(InputConnection inputConnection, EditorInfo attribute); /** * This method is called when {@code {@link #startInput(InputConnection, EditorInfo)} or * {@code {@link #restartInput(InputConnection, EditorInfo)} needs to be dispatched. * * <p>Note: This method is hidden because the {@code startInputToken} that this method is * dealing with is one of internal details, which should not be exposed to the IME developers. * If you override this method, you are responsible for not breaking existing IMEs that expect * {@link #startInput(InputConnection, EditorInfo)} to be still called back.</p> * * @param inputConnection optional specific input connection for communicating with the text * box; if {@code null}, you should use the generic bound input * connection * @param editorInfo information about the text box (typically, an EditText) that requests input * @param restarting {@code false} if this corresponds to * {@link #startInput(InputConnection, EditorInfo)}. Otherwise this * corresponds to {@link #restartInput(InputConnection, EditorInfo)}. * @param startInputToken a token that identifies a logical session that starts with this method * call. Some internal IPCs such as {@link * InputMethodManager#setImeWindowStatus(IBinder, IBinder, int, int)} * require this token to work, and you have to keep the token alive until * the next {@link #startInput(InputConnection, EditorInfo, IBinder)} as * long as your implementation of {@link InputMethod} relies on such * IPCs * @see #startInput(InputConnection, EditorInfo) * @see #restartInput(InputConnection, EditorInfo) * @see EditorInfo * @hide */ default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo, boolean restarting, @NonNull IBinder startInputToken) { if (restarting) { restartInput(inputConnection, editorInfo); } else { startInput(inputConnection, editorInfo); } } /** * Create a new {@link InputMethodSession} that can be handed to client * applications for interacting with the input method. You can later Loading
core/java/android/view/inputmethod/InputMethodManager.java +3 −2 Original line number Diff line number Diff line Loading @@ -739,9 +739,10 @@ public final class InputMethodManager { } /** @hide */ public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) { public void setImeWindowStatus(IBinder imeToken, IBinder startInputToken, int vis, int backDisposition) { try { mService.setImeWindowStatus(imeToken, vis, backDisposition); mService.setImeWindowStatus(imeToken, startInputToken, vis, backDisposition); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
core/java/com/android/internal/os/HandlerCaller.java +10 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,16 @@ public class HandlerCaller { return mH.obtainMessage(what, arg1, arg2, args); } public Message obtainMessageIIOOOO(int what, int arg1, int arg2, Object arg3, Object arg4, Object arg5, Object arg6) { SomeArgs args = SomeArgs.obtain(); args.arg1 = arg3; args.arg2 = arg4; args.arg3 = arg5; args.arg4 = arg6; return mH.obtainMessage(what, arg1, arg2, args); } public Message obtainMessageOO(int what, Object arg1, Object arg2) { SomeArgs args = SomeArgs.obtain(); args.arg1 = arg1; Loading