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

Commit 17827d75 authored by Wilson Wu's avatar Wilson Wu
Browse files

Introduce InputMethodSessionWrapper for InputMethodManager

To simplify InputMethodManager code logic, have a wrapper
class which encapsulates IPCs from InputMethodManager to
InputMethodService.

Bug: 167948374
Test: atest CtsInputMethodTestCases

Change-Id: Ifb4f86098011fe74cf4159446106d6c15c30fa30
parent 76186b25
Loading
Loading
Loading
Loading
+88 −109
Original line number Diff line number Diff line
@@ -462,11 +462,25 @@ public final class InputMethodManager {
     */
    @UnsupportedAppUsage
    String mCurId;

    /**
     * The actual instance of the method to make calls on it.
     * Kept for {@link UnsupportedAppUsage}.  Not officially maintained.
     *
     * @deprecated New code should use {@link #mCurrentInputMethodSession}.
     */
    @Deprecated
    @GuardedBy("mH")
    @Nullable
    @UnsupportedAppUsage
    IInputMethodSession mCurMethod;

    /**
     * Encapsulates IPCs to the currently connected InputMethodService.
     */
    @Nullable
    @GuardedBy("mH")
    private InputMethodSessionWrapper mCurrentInputMethodSession = null;

    InputChannel mCurChannel;
    ImeInputEventSender mCurSender;

@@ -623,11 +637,8 @@ public final class InputMethodManager {
        public void finishInputAndReportToIme() {
            synchronized (mH) {
                finishInputLocked();
                if (mCurMethod != null) {
                    try {
                        mCurMethod.finishInput();
                    } catch (RemoteException e) {
                    }
                if (mCurrentInputMethodSession != null) {
                    mCurrentInputMethodSession.finishInput();
                }
            }
        }
@@ -754,7 +765,8 @@ public final class InputMethodManager {
        @Override
        public boolean hasActiveConnection(View view) {
            synchronized (mH) {
                if (!hasServedByInputMethodLocked(view) || mCurMethod == null) {
                if (!hasServedByInputMethodLocked(view)
                        || mCurrentInputMethodSession == null) {
                    return false;
                }

@@ -861,7 +873,9 @@ public final class InputMethodManager {
                                REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;

                        setInputChannelLocked(res.channel);
                        mCurMethod = res.method;
                        mCurMethod = res.method; // for @UnsupportedAppUsage
                        mCurrentInputMethodSession =
                                InputMethodSessionWrapper.createOrNull(res.method);
                        mCurId = res.id;
                        mBindSequence = res.sequence;
                        mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
@@ -1004,7 +1018,7 @@ public final class InputMethodManager {
                        }
                        mActivityViewToScreenMatrix.setValues(matrixValues);

                        if (mCursorAnchorInfo == null || mCurMethod == null
                        if (mCursorAnchorInfo == null || mCurrentInputMethodSession == null
                                || mServedInputConnectionWrapper == null) {
                            return;
                        }
@@ -1015,13 +1029,9 @@ public final class InputMethodManager {
                        }
                        // Since the host ActivityView is moved, we need to issue
                        // IMS#updateCursorAnchorInfo() again.
                        try {
                            mCurMethod.updateCursorAnchorInfo(
                        mCurrentInputMethodSession.updateCursorAnchorInfo(
                                CursorAnchorInfo.createForAdditionalParentMatrix(
                                        mCursorAnchorInfo, mActivityViewToScreenMatrix));
                        } catch (RemoteException e) {
                            Log.w(TAG, "IME died: " + mCurId, e);
                        }
                    }
                    return;
                }
@@ -1496,7 +1506,8 @@ public final class InputMethodManager {
        setInputChannelLocked(null);
        mBindSequence = -1;
        mCurId = null;
        mCurMethod = null;
        mCurMethod = null; // for @UnsupportedAppUsage
        mCurrentInputMethodSession = null;
    }

    void setInputChannelLocked(InputChannel channel) {
@@ -1560,11 +1571,8 @@ public final class InputMethodManager {
            }

            mCompletions = completions;
            if (mCurMethod != null) {
                try {
                    mCurMethod.displayCompletions(mCompletions);
                } catch (RemoteException e) {
                }
            if (mCurrentInputMethodSession != null) {
                mCurrentInputMethodSession.displayCompletions(mCompletions);
            }
        }
    }
@@ -1583,11 +1591,8 @@ public final class InputMethodManager {
                return;
            }

            if (mCurMethod != null) {
                try {
                    mCurMethod.updateExtractedText(token, text);
                } catch (RemoteException e) {
                }
            if (mCurrentInputMethodSession != null) {
                mCurrentInputMethodSession.updateExtractedText(token, text);
            }
        }
    }
@@ -1848,11 +1853,8 @@ public final class InputMethodManager {
            if (servedView == null || servedView.getWindowToken() != windowToken) {
                return;
            }
            if (mCurMethod != null) {
                try {
                    mCurMethod.toggleSoftInput(showFlags, hideFlags);
                } catch (RemoteException e) {
                }
            if (mCurrentInputMethodSession != null) {
                mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags);
            }
        }
    }
@@ -1873,11 +1875,8 @@ public final class InputMethodManager {
        ImeTracing.getInstance().triggerClientDump(
                "InputMethodManager#toggleSoftInput", InputMethodManager.this,
                null /* icProto */);
        if (mCurMethod != null) {
            try {
                mCurMethod.toggleSoftInput(showFlags, hideFlags);
            } catch (RemoteException e) {
            }
        if (mCurrentInputMethodSession != null) {
            mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags);
        }
    }

@@ -2060,7 +2059,8 @@ public final class InputMethodManager {
                if (res.id != null) {
                    setInputChannelLocked(res.channel);
                    mBindSequence = res.sequence;
                    mCurMethod = res.method;
                    mCurMethod = res.method; // for @UnsupportedAppUsage
                    mCurrentInputMethodSession = InputMethodSessionWrapper.createOrNull(res.method);
                    mCurId = res.id;
                } else if (res.channel != null && res.channel != mCurChannel) {
                    res.channel.dispose();
@@ -2070,11 +2070,8 @@ public final class InputMethodManager {
                        mRestartOnNextWindowFocus = true;
                        break;
                }
                if (mCurMethod != null && mCompletions != null) {
                    try {
                        mCurMethod.displayCompletions(mCompletions);
                    } catch (RemoteException e) {
                    }
                if (mCurrentInputMethodSession != null && mCompletions != null) {
                    mCurrentInputMethodSession.displayCompletions(mCompletions);
                }
            } catch (RemoteException e) {
                Log.w(TAG, "IME died: " + mCurId, e);
@@ -2232,12 +2229,9 @@ public final class InputMethodManager {
        ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
                null /* icProto */);
        synchronized (mH) {
            try {
                if (mCurMethod != null && mCurRootView != null
            if (mCurrentInputMethodSession != null && mCurRootView != null
                    && mCurRootView.getWindowToken() == windowToken) {
                    mCurMethod.notifyImeHidden();
                }
            } catch (RemoteException re) {
                mCurrentInputMethodSession.notifyImeHidden();
            }
        }
    }
@@ -2282,7 +2276,7 @@ public final class InputMethodManager {
        checkFocus();
        synchronized (mH) {
            if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
                    || mCurMethod == null) {
                    || mCurrentInputMethodSession == null) {
                return;
            }

@@ -2291,8 +2285,9 @@ public final class InputMethodManager {
                    || mCursorCandEnd != candidatesEnd) {
                if (DEBUG) Log.d(TAG, "updateSelection");

                try {
                    if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
                if (DEBUG) {
                    Log.v(TAG, "SELECTION CHANGE: " + mCurrentInputMethodSession);
                }
                final int oldSelStart = mCursorSelStart;
                final int oldSelEnd = mCursorSelEnd;
                // Update internal values before sending updateSelection to the IME, because
@@ -2302,11 +2297,8 @@ public final class InputMethodManager {
                mCursorSelEnd = selEnd;
                mCursorCandStart = candidatesStart;
                mCursorCandEnd = candidatesEnd;
                    mCurMethod.updateSelection(oldSelStart, oldSelEnd,
                            selStart, selEnd, candidatesStart, candidatesEnd);
                } catch (RemoteException e) {
                    Log.w(TAG, "IME died: " + mCurId, e);
                }
                mCurrentInputMethodSession.updateSelection(
                        oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
            }
        }
    }
@@ -2340,15 +2332,11 @@ public final class InputMethodManager {
        checkFocus();
        synchronized (mH) {
            if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
                    || mCurMethod == null) {
                    || mCurrentInputMethodSession == null) {
                return;
            }
            try {
            if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
                mCurMethod.viewClicked(focusChanged);
            } catch (RemoteException e) {
                Log.w(TAG, "IME died: " + mCurId, e);
            }
            mCurrentInputMethodSession.viewClicked(focusChanged);
        }
    }

@@ -2409,21 +2397,16 @@ public final class InputMethodManager {
        checkFocus();
        synchronized (mH) {
            if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
                    || mCurMethod == null) {
                    || mCurrentInputMethodSession == null) {
                return;
            }

            mTmpCursorRect.set(left, top, right, bottom);
            if (!mCursorRect.equals(mTmpCursorRect)) {
                if (DEBUG) Log.d(TAG, "updateCursor");
                if (DEBUG) Log.d(TAG, "updateCursor: " + mCurrentInputMethodSession);

                try {
                    if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
                    mCurMethod.updateCursor(mTmpCursorRect);
                mCurrentInputMethodSession.updateCursor(mTmpCursorRect);
                mCursorRect.set(mTmpCursorRect);
                } catch (RemoteException e) {
                    Log.w(TAG, "IME died: " + mCurId, e);
                }
            }
        }
    }
@@ -2446,7 +2429,7 @@ public final class InputMethodManager {
        checkFocus();
        synchronized (mH) {
            if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
                    || mCurMethod == null) {
                    || mCurrentInputMethodSession == null) {
                return;
            }
            // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
@@ -2463,21 +2446,16 @@ public final class InputMethodManager {
                return;
            }
            if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
            try {
            if (mActivityViewToScreenMatrix != null) {
                    mCurMethod.updateCursorAnchorInfo(
                mCurrentInputMethodSession.updateCursorAnchorInfo(
                        CursorAnchorInfo.createForAdditionalParentMatrix(
                            cursorAnchorInfo, mActivityViewToScreenMatrix));
            } else {
                    mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
                mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
            }
            mCursorAnchorInfo = cursorAnchorInfo;
            // Clear immediate bit (if any).
                mRequestUpdateCursorAnchorInfoMonitorMode &=
                        ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
            } catch (RemoteException e) {
                Log.w(TAG, "IME died: " + mCurId, e);
            }
            mRequestUpdateCursorAnchorInfoMonitorMode &= ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
        }
    }

@@ -2503,15 +2481,11 @@ public final class InputMethodManager {
        checkFocus();
        synchronized (mH) {
            if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
                    || mCurMethod == null) {
                    || mCurrentInputMethodSession == null) {
                return;
            }
            try {
            if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
                mCurMethod.appPrivateCommand(action, data);
            } catch (RemoteException e) {
                Log.w(TAG, "IME died: " + mCurId, e);
            }
            mCurrentInputMethodSession.appPrivateCommand(action, data);
        }
    }

@@ -2669,7 +2643,7 @@ public final class InputMethodManager {
    public int dispatchInputEvent(InputEvent event, Object token,
            FinishedInputEventCallback callback, Handler handler) {
        synchronized (mH) {
            if (mCurMethod != null) {
            if (mCurrentInputMethodSession != null) {
                if (event instanceof KeyEvent) {
                    KeyEvent keyEvent = (KeyEvent)event;
                    if (keyEvent.getAction() == KeyEvent.ACTION_DOWN
@@ -2680,7 +2654,9 @@ public final class InputMethodManager {
                    }
                }

                if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod);
                if (DEBUG) {
                    Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurrentInputMethodSession);
                }

                PendingEvent p = obtainPendingEventLocked(
                        event, token, mCurId, callback, handler);
@@ -2770,8 +2746,7 @@ public final class InputMethodManager {
                return DISPATCH_IN_PROGRESS;
            }

            Log.w(TAG, "Unable to send input event to IME: "
                    + mCurId + " dropping: " + event);
            Log.w(TAG, "Unable to send input event to IME: " + mCurId + " dropping: " + event);
        }
        return DISPATCH_NOT_HANDLED;
    }
@@ -3228,7 +3203,11 @@ public final class InputMethodManager {
                + " mBindSequence=" + mBindSequence
                + " mCurId=" + mCurId);
        p.println("  mFullscreenMode=" + mFullscreenMode);
        p.println("  mCurMethod=" + mCurMethod);
        if (mCurrentInputMethodSession != null) {
            p.println("  mCurMethod=" + mCurrentInputMethodSession);
        } else {
            p.println("  mCurMethod= null");
        }
        p.println("  mCurRootView=" + mCurRootView);
        p.println("  mServedView=" + getServedViewLocked());
        p.println("  mNextServedView=" + getNextServedViewLocked());
@@ -3344,7 +3323,7 @@ public final class InputMethodManager {
     */
    @GuardedBy("mH")
    public void dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto) {
        if (mCurMethod == null) {
        if (mCurrentInputMethodSession == null) {
            return;
        }

+163 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.inputmethod;

import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;

import com.android.internal.view.IInputMethodSession;

/**
 * This class wrap the {@link IInputMethodSession} object from {@link InputMethodManager}.
 * Using current {@link IInputMethodSession} object to communicate with
 * {@link android.inputmethodservice.InputMethodService}.
 */
final class InputMethodSessionWrapper {

    private static final String TAG = "InputMethodSessionWrapper";

    /**
     * The actual instance of the method to make calls on it.
     */
    @NonNull
    private final IInputMethodSession mSession;

    private InputMethodSessionWrapper(@NonNull IInputMethodSession inputMethodSession) {
        mSession = inputMethodSession;
    }

    /**
     * Create a {@link InputMethodSessionWrapper} instance if applicability.
     *
     * @param inputMethodSession {@link IInputMethodSession} object to be wrapped.
     * @return an instance of {@link InputMethodSessionWrapper} if {@code inputMethodSession} is not
     *         {@code null}. {@code null} otherwise.
     */
    @Nullable
    public static InputMethodSessionWrapper createOrNull(
            @NonNull IInputMethodSession inputMethodSession) {
        return inputMethodSession != null ? new InputMethodSessionWrapper(inputMethodSession)
                : null;
    }

    @AnyThread
    void finishInput() {
        try {
            mSession.finishInput();
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
        try {
            mSession.updateCursorAnchorInfo(cursorAnchorInfo);
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void displayCompletions(CompletionInfo[] completions) {
        try {
            mSession.displayCompletions(completions);
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void updateExtractedText(int token, ExtractedText text) {
        try {
            mSession.updateExtractedText(token, text);
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void toggleSoftInput(int showFlags, int hideFlags) {
        try {
            mSession.toggleSoftInput(showFlags, hideFlags);
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void appPrivateCommand(String action, Bundle data) {
        try {
            mSession.appPrivateCommand(action, data);
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void notifyImeHidden() {
        try {
            mSession.notifyImeHidden();
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void viewClicked(boolean focusChanged) {
        try {
            mSession.viewClicked(focusChanged);
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void updateCursor(Rect newCursor) {
        try {
            mSession.updateCursor(newCursor);
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    @AnyThread
    void updateSelection(int oldSelStart, int oldSelEnd, int selStart, int selEnd,
            int candidatesStart, int candidatesEnd) {
        try {
            mSession.updateSelection(
                    oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
        } catch (RemoteException e) {
            Log.w(TAG, "IME died", e);
        }
    }

    /**
     * @return {@link IInputMethodSession#toString()} as a debug string.
     */
    @AnyThread
    @NonNull
    @Override
    public String toString() {
        return mSession.toString();
    }
}