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

Commit 92bc6f4c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Implement InputConnection task cancellation"

parents 12e9bb36 5b848f27
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -59,7 +59,8 @@ public final class IInputContextInvoker {

    @NonNull
    InputConnectionCommandHeader createHeader() {
        return new InputConnectionCommandHeader();
        // TODO(b/203086369): Propagate session ID for interruption
        return new InputConnectionCommandHeader(0 /* sessionId */);
    }

    /**
+16 −2
Original line number Diff line number Diff line
@@ -25,7 +25,19 @@ import android.os.Parcelable;
 * {@link android.inputmethodservice.RemoteInputConnection}.
 */
public final class InputConnectionCommandHeader implements Parcelable {
    public InputConnectionCommandHeader() {
    /**
     * An identifier that is to be used when multiplexing multiple sessions into a single
     * {@link com.android.internal.view.IInputContext}.
     *
     * <p>This ID is considered to belong to an implicit namespace defined for each
     * {@link com.android.internal.view.IInputContext} instance.  Uniqueness of the session ID
     * across multiple instances of {@link com.android.internal.view.IInputContext} is not
     * guaranteed unless explicitly noted in a higher layer.</p>
     */
    public final int mSessionId;

    public InputConnectionCommandHeader(int sessionId) {
        mSessionId = sessionId;
    }

    @Override
@@ -38,7 +50,8 @@ public final class InputConnectionCommandHeader implements Parcelable {
            new Parcelable.Creator<InputConnectionCommandHeader>() {
                @NonNull
                public InputConnectionCommandHeader createFromParcel(Parcel in) {
                    return new InputConnectionCommandHeader();
                    final int sessionId = in.readInt();
                    return new InputConnectionCommandHeader(sessionId);
                }

                @NonNull
@@ -49,5 +62,6 @@ public final class InputConnectionCommandHeader implements Parcelable {

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(mSessionId);
    }
}
+123 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import static com.android.internal.inputmethod.InputConnectionProtoDumper.buildG
import static com.android.internal.inputmethod.InputConnectionProtoDumper.buildGetTextAfterCursorProto;
import static com.android.internal.inputmethod.InputConnectionProtoDumper.buildGetTextBeforeCursorProto;

import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
@@ -45,7 +47,9 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.view.IInputContext;

import java.lang.annotation.Retention;
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;

@@ -62,6 +66,11 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
    private static final String TAG = "RemoteInputConnectionImpl";
    private static final boolean DEBUG = false;

    @Retention(SOURCE)
    private @interface Dispatching {
        boolean cancellable();
    }

    @GuardedBy("mLock")
    @Nullable
    private InputConnection mInputConnection;
@@ -77,6 +86,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
    private final InputMethodManager mParentInputMethodManager;
    private final WeakReference<View> mServedView;

    // TODO(b/203086369): This is to be used when interruption is implemented.
    private final AtomicInteger mCurrentSessionId = new AtomicInteger(0);

    public RemoteInputConnectionImpl(@NonNull Looper looper,
            @NonNull InputConnection inputConnection,
            @NonNull InputMethodManager inputMethodManager, @Nullable View servedView) {
@@ -120,6 +132,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
     *
     * <p>Multiple invocations will be simply ignored.</p>
     */
    @Dispatching(cancellable = false)
    public void deactivate() {
        if (isFinished()) {
            // This is a small performance optimization.  Still only the 1st call of
@@ -214,6 +227,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
     * @param enabled the parameter to be passed to
     *                {@link InputConnection#reportFullscreenMode(boolean)}.
     */
    @Dispatching(cancellable = false)
    public void dispatchReportFullscreenMode(boolean enabled) {
        dispatch(() -> {
            final InputConnection ic = getInputConnection();
@@ -224,10 +238,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void getTextAfterCursor(InputConnectionCommandHeader header, int length, int flags,
            AndroidFuture future /* T=CharSequence */) {
        dispatchWithTracing("getTextAfterCursor", future, () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return null;  // cancelled
            }
            final InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
@@ -242,10 +260,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        }, useImeTracing() ? result -> buildGetTextAfterCursorProto(length, flags, result) : null);
    }

    @Dispatching(cancellable = true)
    @Override
    public void getTextBeforeCursor(InputConnectionCommandHeader header, int length, int flags,
            AndroidFuture future /* T=CharSequence */) {
        dispatchWithTracing("getTextBeforeCursor", future, () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return null;  // cancelled
            }
            final InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
@@ -260,10 +282,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        }, useImeTracing() ? result -> buildGetTextBeforeCursorProto(length, flags, result) : null);
    }

    @Dispatching(cancellable = true)
    @Override
    public void getSelectedText(InputConnectionCommandHeader header, int flags,
            AndroidFuture future /* T=CharSequence */) {
        dispatchWithTracing("getSelectedText", future, () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return null;  // cancelled
            }
            final InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "getSelectedText on inactive InputConnection");
@@ -278,10 +304,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        }, useImeTracing() ? result -> buildGetSelectedTextProto(flags, result) : null);
    }

    @Dispatching(cancellable = true)
    @Override
    public void getSurroundingText(InputConnectionCommandHeader header, int beforeLength,
            int afterLength, int flags, AndroidFuture future /* T=SurroundingText */) {
        dispatchWithTracing("getSurroundingText", future, () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return null;  // cancelled
            }
            final InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "getSurroundingText on inactive InputConnection");
@@ -302,10 +332,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
                beforeLength, afterLength, flags, result) : null);
    }

    @Dispatching(cancellable = true)
    @Override
    public void getCursorCapsMode(InputConnectionCommandHeader header, int reqModes,
            AndroidFuture future /* T=Integer */) {
        dispatchWithTracing("getCursorCapsMode", future, () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return 0;  // cancelled
            }
            final InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
@@ -315,10 +349,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        }, useImeTracing() ? result -> buildGetCursorCapsModeProto(reqModes, result) : null);
    }

    @Dispatching(cancellable = true)
    @Override
    public void getExtractedText(InputConnectionCommandHeader header, ExtractedTextRequest request,
            int flags, AndroidFuture future /* T=ExtractedText */) {
        dispatchWithTracing("getExtractedText", future, () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return null;  // cancelled
            }
            final InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "getExtractedText on inactive InputConnection");
@@ -328,10 +366,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        }, useImeTracing() ? result -> buildGetExtractedTextProto(request, flags, result) : null);
    }

    @Dispatching(cancellable = true)
    @Override
    public void commitText(InputConnectionCommandHeader header, CharSequence text,
            int newCursorPosition) {
        dispatchWithTracing("commitText", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "commitText on inactive InputConnection");
@@ -341,9 +383,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void commitCompletion(InputConnectionCommandHeader header, CompletionInfo text) {
        dispatchWithTracing("commitCompletion", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "commitCompletion on inactive InputConnection");
@@ -353,9 +399,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void commitCorrection(InputConnectionCommandHeader header, CorrectionInfo info) {
        dispatchWithTracing("commitCorrection", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "commitCorrection on inactive InputConnection");
@@ -369,9 +419,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void setSelection(InputConnectionCommandHeader header, int start, int end) {
        dispatchWithTracing("setSelection", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "setSelection on inactive InputConnection");
@@ -381,9 +435,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void performEditorAction(InputConnectionCommandHeader header, int id) {
        dispatchWithTracing("performEditorAction", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "performEditorAction on inactive InputConnection");
@@ -393,9 +451,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void performContextMenuAction(InputConnectionCommandHeader header, int id) {
        dispatchWithTracing("performContextMenuAction", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "performContextMenuAction on inactive InputConnection");
@@ -405,9 +467,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void setComposingRegion(InputConnectionCommandHeader header, int start, int end) {
        dispatchWithTracing("setComposingRegion", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "setComposingRegion on inactive InputConnection");
@@ -421,10 +487,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void setComposingText(InputConnectionCommandHeader header, CharSequence text,
            int newCursorPosition) {
        dispatchWithTracing("setComposingText", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "setComposingText on inactive InputConnection");
@@ -439,7 +509,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
     *
     * <p>This method is intended to be called only from {@link InputMethodManager}.</p>
     */
    @Dispatching(cancellable = true)
    public void finishComposingTextFromImm() {
        final int currentSessionId = mCurrentSessionId.get();
        dispatchWithTracing("finishComposingTextFromImm", () -> {
            if (isFinished()) {
                // In this case, #finishComposingText() is guaranteed to be called already.
@@ -449,6 +521,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
                }
                return;
            }
            if (currentSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            // Note we do NOT check isActive() here, because this is safe
            // for an IME to call at any time, and we need to allow it
@@ -462,6 +537,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void finishComposingText(InputConnectionCommandHeader header) {
        dispatchWithTracing("finishComposingText", () -> {
@@ -473,6 +549,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
                }
                return;
            }
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            // Note we do NOT check isActive() here, because this is safe
            // for an IME to call at any time, and we need to allow it
@@ -486,9 +565,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void sendKeyEvent(InputConnectionCommandHeader header, KeyEvent event) {
        dispatchWithTracing("sendKeyEvent", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "sendKeyEvent on inactive InputConnection");
@@ -498,9 +581,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void clearMetaKeyStates(InputConnectionCommandHeader header, int states) {
        dispatchWithTracing("clearMetaKeyStates", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
@@ -510,10 +597,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void deleteSurroundingText(InputConnectionCommandHeader header, int beforeLength,
            int afterLength) {
        dispatchWithTracing("deleteSurroundingText", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
@@ -523,10 +614,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void deleteSurroundingTextInCodePoints(InputConnectionCommandHeader header,
            int beforeLength, int afterLength) {
        dispatchWithTracing("deleteSurroundingTextInCodePoints", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
@@ -540,9 +635,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void beginBatchEdit(InputConnectionCommandHeader header) {
        dispatchWithTracing("beginBatchEdit", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "beginBatchEdit on inactive InputConnection");
@@ -552,9 +651,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void endBatchEdit(InputConnectionCommandHeader header) {
        dispatchWithTracing("endBatchEdit", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "endBatchEdit on inactive InputConnection");
@@ -564,9 +667,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void performSpellCheck(InputConnectionCommandHeader header) {
        dispatchWithTracing("performSpellCheck", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "performSpellCheck on inactive InputConnection");
@@ -576,10 +683,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void performPrivateCommand(InputConnectionCommandHeader header, String action,
            Bundle data) {
        dispatchWithTracing("performPrivateCommand", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "performPrivateCommand on inactive InputConnection");
@@ -589,10 +700,14 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void requestCursorUpdates(InputConnectionCommandHeader header, int cursorUpdateMode,
            int imeDisplayId, AndroidFuture future /* T=Boolean */) {
        dispatchWithTracing("requestCursorUpdates", future, () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return false;  // cancelled
            }
            final InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
@@ -611,11 +726,15 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void commitContent(InputConnectionCommandHeader header,
            InputContentInfo inputContentInfo, int flags, Bundle opts,
            AndroidFuture future /* T=Boolean */) {
        dispatchWithTracing("commitContent", future, () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return false;  // cancelled
            }
            final InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "commitContent on inactive InputConnection");
@@ -634,9 +753,13 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
        });
    }

    @Dispatching(cancellable = true)
    @Override
    public void setImeConsumesInput(InputConnectionCommandHeader header, boolean imeConsumesInput) {
        dispatchWithTracing("setImeConsumesInput", () -> {
            if (header.mSessionId != mCurrentSessionId.get()) {
                return;  // cancelled
            }
            InputConnection ic = getInputConnection();
            if (ic == null || !isActive()) {
                Log.w(TAG, "setImeConsumesInput on inactive InputConnection");