RemoteProxyInputConnection.java

/*
 * Copyright 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 androidx.car.app.activity.renderer.surface;

import static java.util.Objects.requireNonNull;

import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnectionWrapper;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.car.app.activity.ServiceDispatcher;
import androidx.car.app.activity.renderer.IProxyInputConnection;

/** Proxies input connection calls to the provided {@link IProxyInputConnection}. */
final class RemoteProxyInputConnection extends InputConnectionWrapper {
    private final ServiceDispatcher mServiceDispatcher;
    private final IProxyInputConnection mProxyInputConnection;

    RemoteProxyInputConnection(@NonNull ServiceDispatcher serviceDispatcher,
            @NonNull IProxyInputConnection proxyInputConnection) {
        super(null, true);
        mServiceDispatcher = serviceDispatcher;
        mProxyInputConnection = proxyInputConnection;
    }

    @Nullable
    @Override
    public CharSequence getTextBeforeCursor(int n, int flags) {
        return mServiceDispatcher.fetch("getTextBeforeCursor", null, () ->
                mProxyInputConnection.getTextBeforeCursor(n, flags));
    }

    @Nullable
    @Override
    public CharSequence getTextAfterCursor(int n, int flags) {
        return mServiceDispatcher.fetch("getTextAfterCursor", null, () ->
                mProxyInputConnection.getTextAfterCursor(n, flags));
    }

    @Nullable
    @Override
    public CharSequence getSelectedText(int flags) {
        return mServiceDispatcher.fetch("getSelectedText", null, () ->
                mProxyInputConnection.getSelectedText(flags));
    }

    @Override
    public int getCursorCapsMode(int reqModes) {
        Integer res = mServiceDispatcher.fetch("getCursorCapsMode", 0, () ->
                mProxyInputConnection.getCursorCapsMode(reqModes));
        return res != null ? res : 0;
    }

    @Nullable
    @Override
    public ExtractedText getExtractedText(@NonNull ExtractedTextRequest request, int flags) {
        requireNonNull(request);
        return mServiceDispatcher.fetch("getExtractedText", null, () ->
                        mProxyInputConnection.getExtractedText(request, flags));
    }

    @Override
    public boolean deleteSurroundingText(int beforeLength, int afterLength) {
        Boolean success = mServiceDispatcher.fetch("deleteSurroundingText", false, () ->
                mProxyInputConnection.deleteSurroundingText(beforeLength, afterLength));
        return success != null ? success : false;
    }

    @Override
    public boolean setComposingText(@NonNull CharSequence text, int newCursorPosition) {
        requireNonNull(text);
        Boolean success = mServiceDispatcher.fetch("setComposingText", false, () ->
                mProxyInputConnection.setComposingText(text, newCursorPosition));
        return success != null ? success : false;
    }

    @Override
    public boolean setComposingRegion(int start, int end) {
        Boolean success = mServiceDispatcher.fetch("setComposingRegion", false, () ->
                mProxyInputConnection.setComposingRegion(start, end));
        return success != null ? success : false;
    }

    @Override
    public boolean finishComposingText() {
        Boolean success = mServiceDispatcher.fetch("finishComposingText", false,
                mProxyInputConnection::finishComposingText);
        return success != null ? success : false;
    }

    @Override
    public boolean commitText(@NonNull CharSequence text, int newCursorPosition) {
        requireNonNull(text);
        Boolean success = mServiceDispatcher.fetch("commitText", false, () ->
                mProxyInputConnection.commitText(text, newCursorPosition));
        return success != null ? success : false;
    }

    @Override
    public boolean commitCompletion(@NonNull CompletionInfo text) {
        requireNonNull(text);
        Boolean success = mServiceDispatcher.fetch("commitCompletion", false, () ->
                mProxyInputConnection.commitCompletion(text));
        return success != null ? success : false;
    }

    @Override
    public boolean commitCorrection(@NonNull CorrectionInfo correctionInfo) {
        requireNonNull(correctionInfo);
        Boolean success = mServiceDispatcher.fetch("commitCorrection", false, () ->
                mProxyInputConnection.commitCorrection(correctionInfo));
        return success != null ? success : false;
    }

    @Override
    public boolean setSelection(int start, int end) {
        Boolean success = mServiceDispatcher.fetch("setSelection", false, () ->
                mProxyInputConnection.setSelection(start, end));
        return success != null ? success : false;
    }

    @Override
    public boolean performEditorAction(int editorAction) {
        Boolean success = mServiceDispatcher.fetch("performEditorAction", false, () ->
                mProxyInputConnection.performEditorAction(editorAction));
        return success != null ? success : false;
    }

    @Override
    public boolean performContextMenuAction(int id) {
        Boolean success = mServiceDispatcher.fetch("performContextMenuAction", false, () ->
                mProxyInputConnection.performContextMenuAction(id));
        return success != null ? success : false;
    }

    @Override
    public boolean beginBatchEdit() {
        Boolean success = mServiceDispatcher.fetch("beginBatchEdit", false,
                mProxyInputConnection::beginBatchEdit);
        return success != null ? success : false;
    }

    @Override
    public boolean endBatchEdit() {
        Boolean success = mServiceDispatcher.fetch("endBatchEdit", false,
                mProxyInputConnection::endBatchEdit);
        return success != null ? success : false;
    }

    @Override
    public boolean sendKeyEvent(@NonNull KeyEvent event) {
        requireNonNull(event);
        Boolean success = mServiceDispatcher.fetch("sendKeyEvent", false, () ->
                mProxyInputConnection.sendKeyEvent(event));
        return success != null ? success : false;
    }

    @Override
    public boolean clearMetaKeyStates(int states) {
        Boolean success = mServiceDispatcher.fetch("clearMetaKeyStates", false, () ->
                mProxyInputConnection.clearMetaKeyStates(states));
        return success != null ? success : false;
    }

    @Override
    public boolean reportFullscreenMode(boolean enabled) {
        Boolean success = mServiceDispatcher.fetch("requestFullscreenMode", false, () ->
                mProxyInputConnection.reportFullscreenMode(enabled));
        return success != null ? success : false;
    }

    @Override
    public boolean performPrivateCommand(@NonNull String action, @NonNull Bundle data) {
        requireNonNull(action);
        requireNonNull(data);
        Boolean success = mServiceDispatcher.fetch("performPrivateCommand", false, () ->
                mProxyInputConnection.performPrivateCommand(action, data));
        return success != null ? success : false;
    }

    @Override
    public boolean requestCursorUpdates(int cursorUpdateMode) {
        Boolean success = mServiceDispatcher.fetch("requestCursorUpdates", false, () ->
                mProxyInputConnection.requestCursorUpdates(cursorUpdateMode));
        return success != null ? success : false;
    }

    @Override
    public void closeConnection() {
        mServiceDispatcher.dispatch("closeConnection", mProxyInputConnection::closeConnection);
    }

    @Nullable
    @Override
    public Handler getHandler() {
        return null;
    }
}