Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eadb1392 authored by Tarandeep Singh's avatar Tarandeep Singh Committed by Jorim Jaggi
Browse files

Pre-render input method (IME transitions 1/n)

Pre-render input method views and window when EditText receives focus.
This is a pre-requisite for implementing better IME transitions.

Strategy:
Once EditText receives focus, startInput is called. If optimization is
available, IME views and window (SoftInputWindow) are created and
rendered. Until user taps on EditText or showSoftInput() is called, IME
window remains invisible. This pre-rendered window is kept around until
EditorInfo changes or new connection is started (onStartInput).
IME window's visibility will be set using new Insets controller API
rather than conventional client-side dialog.show().

Behavior:
- This is just IME side preparation CL. No performance improvements yet.
- There should be no user perceptible behavior change.
- As long as IME developers were following official lifecycle, they
  shouldn't perceive any behavior change.

Availability:
This optimization, once fully implemented, will be available when:
 - Device is not "Low memory"
 - AND Master flag DebugFlags.FLAG_PRE_RENDER_IME_VIEWS is set.
 - ViewRootImpl.USE_NEW_INSETS_API is enabled

Bug: 118599175
Bug: 111084606
Test: atest CtsInputMethodTestCases
Test: atest CtsInputMethodServiceHostTestCases
Test: atest ActivityManagerMultiDisplayTests
Test: Tested with 4 IMEs and didn't preceive any behavior change.
Scenarios tested:
  1. With and without hardware keyboard
  2. Screen rotation w/ fullscreen mode.
  3. split-screen

Change-Id: I1a6300fe167eb205ee2b4214a6e270a52ebae062
parent 75df50dc
Loading
Loading
Loading
Loading
+17 −9
Original line number Diff line number Diff line
@@ -179,19 +179,24 @@ class IInputMethodWrapper extends IInputMethod.Stub
                return;
            case DO_START_INPUT: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final int missingMethods = msg.arg1;
                final boolean restarting = msg.arg2 != 0;
                final IBinder startInputToken = (IBinder) args.arg1;
                final IInputContext inputContext = (IInputContext) args.arg2;
                final EditorInfo info = (EditorInfo) args.arg3;
                final AtomicBoolean isUnbindIssued = (AtomicBoolean) args.arg4;
                SomeArgs moreArgs = (SomeArgs) args.arg5;
                final InputConnection ic = inputContext != null
                        ? new InputConnectionWrapper(
                                mTarget, inputContext, missingMethods, isUnbindIssued) : null;
                                mTarget, inputContext, moreArgs.argi3, isUnbindIssued)
                        : null;
                info.makeCompatible(mTargetSdkVersion);
                inputMethod.dispatchStartInputWithToken(ic, info, restarting /* restarting */,
                        startInputToken);
                inputMethod.dispatchStartInputWithToken(
                        ic,
                        info,
                        moreArgs.argi1 == 1 /* restarting */,
                        startInputToken,
                        moreArgs.argi2 == 1 /* shouldPreRenderIme */);
                args.recycle();
                moreArgs.recycle();
                return;
            }
            case DO_CREATE_SESSION: {
@@ -291,14 +296,17 @@ class IInputMethodWrapper extends IInputMethod.Stub
    @Override
    public void startInput(IBinder startInputToken, IInputContext inputContext,
            @InputConnectionInspector.MissingMethodFlags final int missingMethods,
            EditorInfo attribute, boolean restarting) {
            EditorInfo attribute, boolean restarting, boolean shouldPreRenderIme) {
        if (mIsUnbindIssued == null) {
            Log.e(TAG, "startInput must be called after bindInput.");
            mIsUnbindIssued = new AtomicBoolean();
        }
        mCaller.executeOrSendMessage(mCaller.obtainMessageIIOOOO(DO_START_INPUT,
                missingMethods, restarting ? 1 : 0, startInputToken, inputContext, attribute,
                mIsUnbindIssued));
        SomeArgs args = SomeArgs.obtain();
        args.argi1 = restarting ? 1 : 0;
        args.argi2 = shouldPreRenderIme ? 1 : 0;
        args.argi3 = missingMethods;
        mCaller.executeOrSendMessage(mCaller.obtainMessageOOOOO(
                DO_START_INPUT, startInputToken, inputContext, attribute, mIsUnbindIssued, args));
    }

    @BinderThread
+170 −75
Original line number Diff line number Diff line
@@ -346,6 +346,13 @@ public class InputMethodService extends AbstractInputMethodService {
     */
    public static final int IME_VISIBLE = 0x2;

    /**
     * @hide
     * The IME is active and ready with views but set invisible.
     * This flag cannot be combined with {@link #IME_VISIBLE}.
     */
    public static final int IME_INVISIBLE = 0x4;

    // Min and max values for back disposition.
    private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
    private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
@@ -362,10 +369,19 @@ public class InputMethodService extends AbstractInputMethodService {
    View mRootView;
    SoftInputWindow mWindow;
    boolean mInitialized;
    boolean mWindowCreated;
    boolean mWindowVisible;
    boolean mWindowWasVisible;
    boolean mViewsCreated;
    // IME views visibility.
    boolean mDecorViewVisible;
    boolean mDecorViewWasVisible;
    boolean mInShowWindow;
    // True if pre-rendering of IME views/window is supported.
    boolean mCanPreRender;
    // If IME is pre-rendered.
    boolean mIsPreRendered;
    // IME window visibility.
    // Use (mDecorViewVisible && mWindowVisible) to check if IME is visible to the user.
    boolean mWindowVisible;

    ViewGroup mFullscreenArea;
    FrameLayout mExtractFrame;
    FrameLayout mCandidatesFrame;
@@ -552,15 +568,18 @@ public class InputMethodService extends AbstractInputMethodService {
         */
        @MainThread
        @Override
        public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
        public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
                @NonNull EditorInfo editorInfo, boolean restarting,
                @NonNull IBinder startInputToken) {
                @NonNull IBinder startInputToken, boolean shouldPreRenderIme) {
            mPrivOps.reportStartInput(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);
            mCanPreRender = shouldPreRenderIme;
            if (DEBUG) Log.v(TAG, "Will Pre-render IME: " + mCanPreRender);

            if (restarting) {
                restartInput(inputConnection, editorInfo);
            } else {
                startInput(inputConnection, editorInfo);
            }
        }

        /**
@@ -570,14 +589,27 @@ public class InputMethodService extends AbstractInputMethodService {
        @Override
        public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
            if (DEBUG) Log.v(TAG, "hideSoftInput()");
            boolean wasVis = isInputViewShown();
            final boolean wasVisible = mIsPreRendered
                    ? mDecorViewVisible && mWindowVisible : isInputViewShown();
            if (mIsPreRendered) {
                // TODO: notify visibility to insets consumer.
                if (DEBUG) {
                    Log.v(TAG, "Making IME window invisible");
                }
                setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
                onPreRenderedWindowVisibilityChanged(false /* setVisible */);
            } else {
                mShowInputFlags = 0;
                mShowInputRequested = false;
                doHideWindow();
            }
            final boolean isVisible = mIsPreRendered
                    ? mDecorViewVisible && mWindowVisible : isInputViewShown();
            final boolean visibilityChanged = isVisible != wasVisible;
            if (resultReceiver != null) {
                resultReceiver.send(wasVis != isInputViewShown()
                resultReceiver.send(visibilityChanged
                        ? InputMethodManager.RESULT_HIDDEN
                        : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
                        : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
                                : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
            }
        }
@@ -589,17 +621,28 @@ public class InputMethodService extends AbstractInputMethodService {
        @Override
        public void showSoftInput(int flags, ResultReceiver resultReceiver) {
            if (DEBUG) Log.v(TAG, "showSoftInput()");
            boolean wasVis = isInputViewShown();
            final boolean wasVisible = mIsPreRendered
                    ? mDecorViewVisible && mWindowVisible : isInputViewShown();
            if (dispatchOnShowInputRequested(flags, false)) {
                if (mIsPreRendered) {
                    // TODO: notify visibility to insets consumer.
                    if (DEBUG) {
                        Log.v(TAG, "Making IME window visible");
                    }
                    onPreRenderedWindowVisibilityChanged(true /* setVisible */);
                } else {
                    showWindow(true);
                }
            }
            // If user uses hard keyboard, IME button should always be shown.
            setImeWindowStatus(mapToImeWindowStatus(isInputViewShown()), mBackDisposition);

            setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
            final boolean isVisible = mIsPreRendered
                    ? mDecorViewVisible && mWindowVisible : isInputViewShown();
            final boolean visibilityChanged = isVisible != wasVisible;
            if (resultReceiver != null) {
                resultReceiver.send(wasVis != isInputViewShown()
                resultReceiver.send(visibilityChanged
                        ? InputMethodManager.RESULT_SHOWN
                        : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
                        : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
                                : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
            }
        }
@@ -972,7 +1015,7 @@ public class InputMethodService extends AbstractInputMethodService {

    void initViews() {
        mInitialized = false;
        mWindowCreated = false;
        mViewsCreated = false;
        mShowInputRequested = false;
        mShowInputFlags = 0;

@@ -1046,7 +1089,7 @@ public class InputMethodService extends AbstractInputMethodService {
    }

    private void resetStateForNewConfiguration() {
        boolean visible = mWindowVisible;
        boolean visible = mDecorViewVisible;
        int showFlags = mShowInputFlags;
        boolean showingInput = mShowInputRequested;
        CompletionInfo[] completions = mCurCompletions;
@@ -1129,7 +1172,7 @@ public class InputMethodService extends AbstractInputMethodService {
            return;
        }
        mBackDisposition = disposition;
        setImeWindowStatus(mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
        setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
    }

    /**
@@ -1380,7 +1423,7 @@ public class InputMethodService extends AbstractInputMethodService {
            mExtractFrame.setVisibility(View.GONE);
        }
        updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
        if (mWindowWasVisible && mFullscreenArea.getVisibility() != vis) {
        if (mDecorViewWasVisible && mFullscreenArea.getVisibility() != vis) {
            int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
                    ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
                    : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
@@ -1439,7 +1482,7 @@ public class InputMethodService extends AbstractInputMethodService {
     */
    public void updateInputViewShown() {
        boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
        if (mIsInputViewShown != isShown && mWindowVisible) {
        if (mIsInputViewShown != isShown && mDecorViewVisible) {
            mIsInputViewShown = isShown;
            mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
            if (mInputView == null) {
@@ -1465,7 +1508,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * applied by {@link #updateInputViewShown()}.
     */
    public boolean isInputViewShown() {
        return mIsInputViewShown && mWindowVisible;
        return mCanPreRender ? mWindowVisible : mIsInputViewShown && mDecorViewVisible;
    }

    /**
@@ -1499,7 +1542,7 @@ public class InputMethodService extends AbstractInputMethodService {
     */
    public void setCandidatesViewShown(boolean shown) {
        updateCandidatesVisibility(shown);
        if (!mShowInputRequested && mWindowVisible != shown) {
        if (!mShowInputRequested && mDecorViewVisible != shown) {
            // If we are being asked to show the candidates view while the app
            // has not asked for the input view to be shown, then we need
            // to update whether the window is shown.
@@ -1804,7 +1847,8 @@ public class InputMethodService extends AbstractInputMethodService {
    public void showWindow(boolean showInput) {
        if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
                + " mShowInputRequested=" + mShowInputRequested
                + " mWindowCreated=" + mWindowCreated
                + " mViewsCreated=" + mViewsCreated
                + " mDecorViewVisible=" + mDecorViewVisible
                + " mWindowVisible=" + mWindowVisible
                + " mInputStarted=" + mInputStarted
                + " mShowInputFlags=" + mShowInputFlags);
@@ -1814,18 +1858,42 @@ public class InputMethodService extends AbstractInputMethodService {
            return;
        }

        mWindowWasVisible = mWindowVisible;
        mDecorViewWasVisible = mDecorViewVisible;
        mInShowWindow = true;
        showWindowInner(showInput);
        mWindowWasVisible = true;
        boolean isPreRenderedAndInvisible = mIsPreRendered && !mWindowVisible;
        final int previousImeWindowStatus =
                (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown()
                        ? (isPreRenderedAndInvisible ? IME_INVISIBLE : IME_VISIBLE) : 0);
        startViews(prepareWindow(showInput));
        final int nextImeWindowStatus = mapToImeWindowStatus();
        if (previousImeWindowStatus != nextImeWindowStatus) {
            setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
        }

        // compute visibility
        onWindowShown();
        mIsPreRendered = mCanPreRender;
        if (mIsPreRendered) {
            onPreRenderedWindowVisibilityChanged(true /* setVisible */);
        } else {
            // Pre-rendering not supported.
            if (DEBUG) Log.d(TAG, "No pre-rendering supported");
            mWindowVisible = true;
        }

        // request draw for the IME surface.
        // When IME is not pre-rendered, this will actually show the IME.
        if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
            if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
            mWindow.show();
        }
        mDecorViewWasVisible = true;
        mInShowWindow = false;
    }

    void showWindowInner(boolean showInput) {
    private boolean prepareWindow(boolean showInput) {
        boolean doShowInput = false;
        final int previousImeWindowStatus =
                (mWindowVisible ? IME_ACTIVE : 0) | (isInputViewShown() ? IME_VISIBLE : 0);
        mWindowVisible = true;
        mDecorViewVisible = true;
        if (!mShowInputRequested && mInputStarted && showInput) {
            doShowInput = true;
            mShowInputRequested = true;
@@ -1836,8 +1904,8 @@ public class InputMethodService extends AbstractInputMethodService {
        updateFullscreenMode();
        updateInputViewShown();

        if (!mWindowCreated) {
            mWindowCreated = true;
        if (!mViewsCreated) {
            mViewsCreated = true;
            initialize();
            if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
            View v = onCreateCandidatesView();
@@ -1846,6 +1914,10 @@ public class InputMethodService extends AbstractInputMethodService {
                setCandidatesView(v);
            }
        }
        return doShowInput;
    }

    private void startViews(boolean doShowInput) {
        if (mShowInputRequested) {
            if (!mInputViewStarted) {
                if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
@@ -1857,29 +1929,26 @@ public class InputMethodService extends AbstractInputMethodService {
            mCandidatesViewStarted = true;
            onStartCandidatesView(mInputEditorInfo, false);
        }
        
        if (doShowInput) {
            startExtractingText(false);
        if (doShowInput) startExtractingText(false);
    }

        final int nextImeWindowStatus = mapToImeWindowStatus(isInputViewShown());
        if (previousImeWindowStatus != nextImeWindowStatus) {
            setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
        }
        if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
            if (DEBUG) Log.v(TAG, "showWindow: showing!");
    private void onPreRenderedWindowVisibilityChanged(boolean setVisible) {
        mWindowVisible = setVisible;
        mShowInputFlags = setVisible ? mShowInputFlags : 0;
        mShowInputRequested = setVisible;
        mDecorViewVisible = setVisible;
        if (setVisible) {
            onWindowShown();
            mWindow.show();
        }
    }

    private void finishViews() {
    private void finishViews(boolean finishingInput) {
        if (mInputViewStarted) {
            if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
            onFinishInputView(false);
            onFinishInputView(finishingInput);
        } else if (mCandidatesViewStarted) {
            if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
            onFinishCandidatesView(false);
            onFinishCandidatesView(finishingInput);
        }
        mInputViewStarted = false;
        mCandidatesViewStarted = false;
@@ -1891,12 +1960,15 @@ public class InputMethodService extends AbstractInputMethodService {
    }

    public void hideWindow() {
        finishViews();
        if (mWindowVisible) {
            mWindow.hide();
        if (DEBUG) Log.v(TAG, "CALL: hideWindow");
        mIsPreRendered = false;
        mWindowVisible = false;
        finishViews(false /* finishingInput */);
        if (mDecorViewVisible) {
            mWindow.hide();
            mDecorViewVisible = false;
            onWindowHidden();
            mWindowWasVisible = false;
            mDecorViewWasVisible = false;
        }
        updateFullscreenMode();
    }
@@ -1956,15 +2028,8 @@ public class InputMethodService extends AbstractInputMethodService {
    }
    
    void doFinishInput() {
        if (mInputViewStarted) {
            if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
            onFinishInputView(true);
        } else if (mCandidatesViewStarted) {
            if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
            onFinishCandidatesView(true);
        }
        mInputViewStarted = false;
        mCandidatesViewStarted = false;
        if (DEBUG) Log.v(TAG, "CALL: doFinishInput");
        finishViews(true /* finishingInput */);
        if (mInputStarted) {
            if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
            onFinishInput();
@@ -1984,7 +2049,7 @@ public class InputMethodService extends AbstractInputMethodService {
        initialize();
        if (DEBUG) Log.v(TAG, "CALL: onStartInput");
        onStartInput(attribute, restarting);
        if (mWindowVisible) {
        if (mDecorViewVisible) {
            if (mShowInputRequested) {
                if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
                mInputViewStarted = true;
@@ -1995,6 +2060,31 @@ public class InputMethodService extends AbstractInputMethodService {
                mCandidatesViewStarted = true;
                onStartCandidatesView(mInputEditorInfo, restarting);
            }
        } else if (mCanPreRender && mInputEditorInfo != null && mStartedInputConnection != null) {
            // Pre-render IME views and window when real EditorInfo is available.
            // pre-render IME window and keep it invisible.
            if (DEBUG) Log.v(TAG, "Pre-Render IME for " + mInputEditorInfo.fieldName);
            if (mInShowWindow) {
                Log.w(TAG, "Re-entrance in to showWindow");
                return;
            }

            mDecorViewWasVisible = mDecorViewVisible;
            mInShowWindow = true;
            startViews(prepareWindow(true /* showInput */));

            // compute visibility
            mIsPreRendered = true;
            onPreRenderedWindowVisibilityChanged(false /* setVisible */);

            // request draw for the IME surface.
            // When IME is not pre-rendered, this will actually show the IME.
            if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
            mWindow.show();
            mDecorViewWasVisible = true;
            mInShowWindow = false;
        } else {
            mIsPreRendered = false;
        }
    }
    
@@ -2146,7 +2236,7 @@ public class InputMethodService extends AbstractInputMethodService {
            // consume the back key.
            if (doIt) requestHideSelf(0);
            return true;
        } else if (mWindowVisible) {
        } else if (mDecorViewVisible) {
            if (mCandidatesVisibility == View.VISIBLE) {
                // If we are showing candidates even if no input area, then
                // hide them.
@@ -2173,7 +2263,6 @@ public class InputMethodService extends AbstractInputMethodService {
        return mExtractEditText;
    }


    /**
     * Called back when a {@link KeyEvent} is forwarded from the target application.
     *
@@ -2886,8 +2975,11 @@ public class InputMethodService extends AbstractInputMethodService {
        inputContentInfo.setUriToken(uriToken);
    }

    private static int mapToImeWindowStatus(boolean isInputViewShown) {
        return IME_ACTIVE | (isInputViewShown ? IME_VISIBLE : 0);
    private int mapToImeWindowStatus() {
        return IME_ACTIVE
                | (isInputViewShown()
                        ? (mCanPreRender ? (mWindowVisible ? IME_VISIBLE : IME_INVISIBLE)
                        : IME_VISIBLE) : 0);
    }

    /**
@@ -2897,9 +2989,10 @@ public class InputMethodService extends AbstractInputMethodService {
    @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
        final Printer p = new PrintWriterPrinter(fout);
        p.println("Input method service state for " + this + ":");
        p.println("  mWindowCreated=" + mWindowCreated);
        p.println("  mWindowVisible=" + mWindowVisible
                + " mWindowWasVisible=" + mWindowWasVisible
        p.println("  mViewsCreated=" + mViewsCreated);
        p.println("  mDecorViewVisible=" + mDecorViewVisible
                + " mDecorViewWasVisible=" + mDecorViewWasVisible
                + " mWindowVisible=" + mWindowVisible
                + " mInShowWindow=" + mInShowWindow);
        p.println("  Configuration=" + getResources().getConfiguration());
        p.println("  mToken=" + mToken);
@@ -2919,6 +3012,8 @@ public class InputMethodService extends AbstractInputMethodService {
        
        p.println("  mShowInputRequested=" + mShowInputRequested
                + " mLastShowInputRequested=" + mLastShowInputRequested
                + " mCanPreRender=" + mCanPreRender
                + " mIsPreRendered=" + mIsPreRendered
                + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
        p.println("  mCandidatesVisibility=" + mCandidatesVisibility
                + " mFullscreenApplied=" + mFullscreenApplied
+1 −1
Original line number Diff line number Diff line
@@ -219,7 +219,7 @@ public interface InputMethod {
    @MainThread
    default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
            @NonNull EditorInfo editorInfo, boolean restarting,
            @NonNull IBinder startInputToken) {
            @NonNull IBinder startInputToken, boolean shouldPreRenderIme) {
        if (restarting) {
            restartInput(inputConnection, editorInfo);
        } else {
+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ public final class InputMethodPrivilegedOperations {
     * @param backDisposition disposition flags
     * @see android.inputmethodservice.InputMethodService#IME_ACTIVE
     * @see android.inputmethodservice.InputMethodService#IME_VISIBLE
     * @see android.inputmethodservice.InputMethodService#IME_INVISIBLE
     * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT
     * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_ADJUST_NOTHING
     */
+1 −1
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ oneway interface IInputMethod {
    void unbindInput();

    void startInput(in IBinder startInputToken, in IInputContext inputContext, int missingMethods,
            in EditorInfo attribute, boolean restarting);
            in EditorInfo attribute, boolean restarting, boolean preRenderImeViews);

    void createSession(in InputChannel channel, IInputSessionCallback callback);

Loading