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

Commit af47729a authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

Merge ControlledInputConnectionWrapper into parent class

Since ControlledInputConnectionWrapper is the only derived class
of IInputConnectionWrapper hence it doesn't have a reason keep them
separate.

Bug: 167948374
Bug: 163450598
Test: atest CtsInputMethodTestCases
Change-Id: Ice1ea23dcb2351b56ef03b507d8aec8f8fb7b30a
parent f4f6a9eb
Loading
Loading
Loading
Loading
+6 −80
Original line number Original line Diff line number Diff line
@@ -106,7 +106,6 @@ import com.android.internal.view.InputBindResult;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.Proxy;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Collections;
import java.util.Collections;
@@ -413,7 +412,7 @@ public final class InputMethodManager {
     * The InputConnection that was last retrieved from the served view.
     * The InputConnection that was last retrieved from the served view.
     */
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    ControlledInputConnectionWrapper mServedInputConnectionWrapper;
    IInputConnectionWrapper mServedInputConnectionWrapper;
    /**
    /**
     * The completions that were last provided by the served view.
     * The completions that were last provided by the served view.
     */
     */
@@ -740,8 +739,7 @@ public final class InputMethodManager {
        /**
        /**
         * Checks whether the active input connection (if any) is for the given view.
         * Checks whether the active input connection (if any) is for the given view.
         *
         *
         * TODO(b/160968797): Remove this method and move mServedInputConnectionWrapper to
         * TODO(b/182259171): Clean-up hasActiveConnection to simplify the logic.
         *  ImeFocusController.
         *
         *
         * Note that this method is only intended for restarting input after focus gain
         * Note that this method is only intended for restarting input after focus gain
         * (e.g. b/160391516), DO NOT leverage this method to do another check.
         * (e.g. b/160391516), DO NOT leverage this method to do another check.
@@ -755,7 +753,7 @@ public final class InputMethodManager {


                return mServedInputConnectionWrapper != null
                return mServedInputConnectionWrapper != null
                        && mServedInputConnectionWrapper.isActive()
                        && mServedInputConnectionWrapper.isActive()
                        && mServedInputConnectionWrapper.mServedView.get() == view;
                        && mServedInputConnectionWrapper.getServedView() == view;
            }
            }
        }
        }
    }
    }
@@ -1022,77 +1020,6 @@ public final class InputMethodManager {
        }
        }
    }
    }


    private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
        private final InputMethodManager mParentInputMethodManager;
        private final WeakReference<View> mServedView;

        ControlledInputConnectionWrapper(Looper icLooper, InputConnection conn,
                InputMethodManager inputMethodManager, View servedView) {
            super(icLooper, conn);
            mParentInputMethodManager = inputMethodManager;
            mServedView = new WeakReference<>(servedView);
        }

        @Override
        public boolean isActive() {
            return mParentInputMethodManager.mActive && !isFinished();
        }

        @Override
        public InputMethodManager getIMM() {
            return mParentInputMethodManager;
        }

        void deactivate() {
            if (isFinished()) {
                // This is a small performance optimization.  Still only the 1st call of
                // reportFinish() will take effect.
                return;
            }
            closeConnection();

            // Notify the app that the InputConnection was closed.
            final View servedView = mServedView.get();
            if (servedView != null) {
                final Handler handler = servedView.getHandler();
                // The handler is null if the view is already detached. When that's the case, for
                // now, we simply don't dispatch this callback.
                if (handler != null) {
                    if (DEBUG) {
                        Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
                    }
                    if (handler.getLooper().isCurrentThread()) {
                        servedView.onInputConnectionClosedInternal();
                    } else {
                        handler.post(servedView::onInputConnectionClosedInternal);
                    }
                }
            }
        }

        @Override
        public String toString() {
            return "ControlledInputConnectionWrapper{"
                    + "connection=" + getInputConnection()
                    + " finished=" + isFinished()
                    + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
                    + " mServedView=" + mServedView.get()
                    + "}";
        }

        void dumpDebug(ProtoOutputStream proto, long fieldId) {
            // Check that the call is initiated in the main thread of the current InputConnection
            // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
            // executed on this thread. Otherwise the messages are dispatched to the correct thread
            // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
            // reasons.
            if (getInputConnection() instanceof DumpableInputConnection && Looper.myLooper()
                    == getLooper()) {
                ((DumpableInputConnection) getInputConnection()).dumpDebug(proto, fieldId);
            }
        }
    }

    final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
    final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
        @Override
        @Override
        protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
        protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
@@ -1256,8 +1183,7 @@ public final class InputMethodManager {
        mMainLooper = looper;
        mMainLooper = looper;
        mH = new H(looper);
        mH = new H(looper);
        mDisplayId = displayId;
        mDisplayId = displayId;
        mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this,
        mIInputContext = new IInputConnectionWrapper(looper, mDummyInputConnection, this, null);
                null);
    }
    }


    /**
    /**
@@ -2063,7 +1989,7 @@ public final class InputMethodManager {
                mServedInputConnectionWrapper.deactivate();
                mServedInputConnectionWrapper.deactivate();
                mServedInputConnectionWrapper = null;
                mServedInputConnectionWrapper = null;
            }
            }
            ControlledInputConnectionWrapper servedContext;
            IInputConnectionWrapper servedContext;
            final int missingMethodFlags;
            final int missingMethodFlags;
            if (ic != null) {
            if (ic != null) {
                mCursorSelStart = tba.initialSelStart;
                mCursorSelStart = tba.initialSelStart;
@@ -2080,7 +2006,7 @@ public final class InputMethodManager {
                } else {
                } else {
                    icHandler = ic.getHandler();
                    icHandler = ic.getHandler();
                }
                }
                servedContext = new ControlledInputConnectionWrapper(
                servedContext = new IInputConnectionWrapper(
                        icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
                        icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
            } else {
            } else {
                servedContext = null;
                servedContext = null;
+82 −18
Original line number Original line Diff line number Diff line
@@ -31,8 +31,10 @@ import android.util.imetracing.ImeTracing;
import android.util.imetracing.InputConnectionHelper;
import android.util.imetracing.InputConnectionHelper;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.DumpableInputConnection;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnection;
@@ -49,7 +51,9 @@ import com.android.internal.inputmethod.IIntResultCallback;
import com.android.internal.inputmethod.ISurroundingTextResultCallback;
import com.android.internal.inputmethod.ISurroundingTextResultCallback;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.SomeArgs;


public abstract class IInputConnectionWrapper extends IInputContext.Stub {
import java.lang.ref.WeakReference;

public final class IInputConnectionWrapper extends IInputContext.Stub {
    private static final String TAG = "IInputConnectionWrapper";
    private static final String TAG = "IInputConnectionWrapper";
    private static final boolean DEBUG = false;
    private static final boolean DEBUG = false;


@@ -90,10 +94,13 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
    private Looper mMainLooper;
    private Looper mMainLooper;
    private Handler mH;
    private Handler mH;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private Object mLock = new Object();
    private final Object mLock = new Object();
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private boolean mFinished = false;
    private boolean mFinished = false;


    private final InputMethodManager mParentInputMethodManager;
    private final WeakReference<View> mServedView;

    class MyHandler extends Handler {
    class MyHandler extends Handler {
        MyHandler(Looper looper) {
        MyHandler(Looper looper) {
            super(looper);
            super(looper);
@@ -105,10 +112,14 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
        }
        }
    }
    }


    public IInputConnectionWrapper(Looper mainLooper, @NonNull InputConnection inputConnection) {
    public IInputConnectionWrapper(@NonNull Looper mainLooper,
            @NonNull InputConnection inputConnection,
            @NonNull InputMethodManager inputMethodManager, @Nullable View servedView) {
        mInputConnection = inputConnection;
        mInputConnection = inputConnection;
        mMainLooper = mainLooper;
        mMainLooper = mainLooper;
        mH = new MyHandler(mMainLooper);
        mH = new MyHandler(mMainLooper);
        mParentInputMethodManager = inputMethodManager;
        mServedView = new WeakReference<>(servedView);
    }
    }


    @Nullable
    @Nullable
@@ -118,21 +129,70 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
        }
        }
    }
    }


    protected Looper getLooper() {
    private boolean isFinished() {
        synchronized (mMainLooper) {
        synchronized (mLock) {
            return mMainLooper;
            return mFinished;
        }
        }
    }
    }


    protected boolean isFinished() {
    public boolean isActive() {
        synchronized (mLock) {
        return mParentInputMethodManager.isActive() && !isFinished();
            return mFinished;
    }
    }

    public View getServedView() {
        return mServedView.get();
    }
    }


    protected abstract boolean isActive();
    public void deactivate() {
        if (isFinished()) {
            // This is a small performance optimization.  Still only the 1st call of
            // reportFinish() will take effect.
            return;
        }
        closeConnection();


    protected abstract InputMethodManager getIMM();
        // Notify the app that the InputConnection was closed.
        final View servedView = mServedView.get();
        if (servedView != null) {
            final Handler handler = servedView.getHandler();
            // The handler is null if the view is already detached. When that's the case, for
            // now, we simply don't dispatch this callback.
            if (handler != null) {
                if (DEBUG) {
                    Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
                }
                if (handler.getLooper().isCurrentThread()) {
                    servedView.onInputConnectionClosedInternal();
                } else {
                    handler.post(servedView::onInputConnectionClosedInternal);
                }
            }
        }
    }

    @Override
    public String toString() {
        return "IInputConnectionWrapper{"
                + "connection=" + getInputConnection()
                + " finished=" + isFinished()
                + " mParentInputMethodManager.isActive()=" + mParentInputMethodManager.isActive()
                + " mServedView=" + mServedView.get()
                + "}";
    }

    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
        synchronized (mLock) {
            // Check that the call is initiated in the main thread of the current InputConnection
            // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
            // executed on this thread. Otherwise the messages are dispatched to the correct thread
            // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
            // reasons.
            if ((mInputConnection instanceof DumpableInputConnection)
                    && Looper.myLooper() == mMainLooper) {
                ((DumpableInputConnection) mInputConnection).dumpDebug(proto, fieldId);
            }
        }
    }


    public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
    public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
        dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
        dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
@@ -161,6 +221,10 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
        dispatchMessage(mH.obtainMessage(DO_GET_SURROUNDING_TEXT, flags, 0 /* unused */, args));
        dispatchMessage(mH.obtainMessage(DO_GET_SURROUNDING_TEXT, flags, 0 /* unused */, args));
    }
    }


    public void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
         // no-op
    }

    public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
    public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
        dispatchMessage(
        dispatchMessage(
                mH.obtainMessage(DO_GET_CURSOR_CAPS_MODE, reqModes, 0 /* unused */, callback));
                mH.obtainMessage(DO_GET_CURSOR_CAPS_MODE, reqModes, 0 /* unused */, callback));
@@ -309,7 +373,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
                        icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1,
                        icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1,
                                msg.arg2, result);
                                msg.arg2, result);
                        ImeTracing.getInstance().triggerClientDump(
                        ImeTracing.getInstance().triggerClientDump(
                                TAG + "#getTextAfterCursor", getIMM(), icProto);
                                TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
                    }
                    }
                    try {
                    try {
                        callback.onResult(result);
                        callback.onResult(result);
@@ -339,7 +403,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
                        icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1,
                        icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1,
                                msg.arg2, result);
                                msg.arg2, result);
                        ImeTracing.getInstance().triggerClientDump(
                        ImeTracing.getInstance().triggerClientDump(
                                TAG + "#getTextBeforeCursor", getIMM(), icProto);
                                TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
                    }
                    }
                    try {
                    try {
                        callback.onResult(result);
                        callback.onResult(result);
@@ -368,7 +432,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
                    if (ImeTracing.getInstance().isEnabled()) {
                    if (ImeTracing.getInstance().isEnabled()) {
                        icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result);
                        icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result);
                        ImeTracing.getInstance().triggerClientDump(
                        ImeTracing.getInstance().triggerClientDump(
                                TAG + "#getSelectedText", getIMM(), icProto);
                                TAG + "#getSelectedText", mParentInputMethodManager, icProto);
                    }
                    }
                    try {
                    try {
                        callback.onResult(result);
                        callback.onResult(result);
@@ -402,7 +466,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
                        icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength,
                        icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength,
                                afterLength, flags, result);
                                afterLength, flags, result);
                        ImeTracing.getInstance().triggerClientDump(
                        ImeTracing.getInstance().triggerClientDump(
                                TAG + "#getSurroundingText", getIMM(), icProto);
                                TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
                    }
                    }
                    try {
                    try {
                        callback.onResult(result);
                        callback.onResult(result);
@@ -432,7 +496,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
                        icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1,
                        icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1,
                                result);
                                result);
                        ImeTracing.getInstance().triggerClientDump(
                        ImeTracing.getInstance().triggerClientDump(
                                TAG + "#getCursorCapsMode", getIMM(), icProto);
                                TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
                    }
                    }
                    try {
                    try {
                        callback.onResult(result);
                        callback.onResult(result);
@@ -464,7 +528,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
                        icProto = InputConnectionHelper.buildGetExtractedTextProto(request,
                        icProto = InputConnectionHelper.buildGetExtractedTextProto(request,
                                msg.arg1, result);
                                msg.arg1, result);
                        ImeTracing.getInstance().triggerClientDump(
                        ImeTracing.getInstance().triggerClientDump(
                                TAG + "#getExtractedText", getIMM(), icProto);
                                TAG + "#getExtractedText", mParentInputMethodManager, icProto);
                    }
                    }
                    try {
                    try {
                        callback.onResult(result);
                        callback.onResult(result);