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

Commit 538f3693 authored by Yohei Yukawa's avatar Yohei Yukawa Committed by Android (Google) Code Review
Browse files

Merge "Let A11yIME use its own IPC definitions" into tm-dev

parents 500043a4 c60176c1
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.accessibilityservice;

import android.view.inputmethod.EditorInfo;

import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;

interface AccessibilityInputMethodSession {
    void finishInput();

    void updateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd,
            int candidatesStart, int candidatesEnd);

    void invalidateInput(EditorInfo editorInfo, IRemoteAccessibilityInputConnection connection,
            int sessionId);

    void setEnabled(boolean enabled);
}
+116 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.accessibilityservice;

import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.view.inputmethod.EditorInfo;

import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;

import java.util.concurrent.atomic.AtomicReference;

final class AccessibilityInputMethodSessionWrapper extends IAccessibilityInputMethodSession.Stub {
    private final Handler mHandler;

    @NonNull
    private final AtomicReference<AccessibilityInputMethodSession> mSessionRef;

    AccessibilityInputMethodSessionWrapper(
            @NonNull Looper looper, @NonNull AccessibilityInputMethodSession session) {
        mSessionRef = new AtomicReference<>(session);
        mHandler = Handler.createAsync(looper);
    }

    @AnyThread
    @Nullable
    AccessibilityInputMethodSession getSession() {
        return mSessionRef.get();
    }

    @Override
    public void updateSelection(int oldSelStart, int oldSelEnd,
            int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
        if (mHandler.getLooper().isCurrentThread()) {
            doUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart,
                    candidatesEnd);
        } else {
            mHandler.post(() -> doUpdateSelection(oldSelStart, oldSelEnd, newSelStart,
                    newSelEnd, candidatesStart, candidatesEnd));
        }
    }

    private void doUpdateSelection(int oldSelStart, int oldSelEnd,
            int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
        final AccessibilityInputMethodSession session = mSessionRef.get();
        if (session != null) {
            session.updateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart,
                    candidatesEnd);
        }
    }

    @Override
    public void finishInput() {
        if (mHandler.getLooper().isCurrentThread()) {
            doFinishInput();
        } else {
            mHandler.post(this::doFinishInput);
        }
    }

    private void doFinishInput() {
        final AccessibilityInputMethodSession session = mSessionRef.get();
        if (session != null) {
            session.finishInput();
        }
    }

    @Override
    public void finishSession() {
        if (mHandler.getLooper().isCurrentThread()) {
            doFinishSession();
        } else {
            mHandler.post(this::doFinishSession);
        }
    }

    private void doFinishSession() {
        mSessionRef.set(null);
    }

    @Override
    public void invalidateInput(EditorInfo editorInfo,
            IRemoteAccessibilityInputConnection connection, int sessionId) {
        if (mHandler.getLooper().isCurrentThread()) {
            doInvalidateInput(editorInfo, connection, sessionId);
        } else {
            mHandler.post(() -> doInvalidateInput(editorInfo, connection, sessionId));
        }
    }

    private void doInvalidateInput(EditorInfo editorInfo,
            IRemoteAccessibilityInputConnection connection, int sessionId) {
        final AccessibilityInputMethodSession session = mSessionRef.get();
        if (session != null) {
            session.invalidateInput(editorInfo, connection, sessionId);
        }
    }
}
+38 −95
Original line number Diff line number Diff line
@@ -40,8 +40,6 @@ import android.graphics.ParcelableColorSpace;
import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
import android.inputmethodservice.IInputMethodSessionWrapper;
import android.inputmethodservice.RemoteInputConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -68,22 +66,19 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodSession;

import com.android.internal.inputmethod.CancellationGroup;
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.RemoteAccessibilityInputConnection;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.IInputSessionWithIdCallback;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
@@ -639,20 +634,10 @@ public abstract class AccessibilityService extends Service {
        /** This is called when the system action list is changed. */
        void onSystemActionsChanged();
        /** This is called when an app requests ime sessions or when the service is enabled. */
        void createImeSession(IInputSessionWithIdCallback callback);
        /**
         * This is called when InputMethodManagerService requests to set the session enabled or
         * disabled
         */
        void setImeSessionEnabled(InputMethodSession session, boolean enabled);
        /** This is called when an app binds input or when the service is enabled. */
        void bindInput(InputBinding binding);
        /** This is called when an app unbinds input or when the service is disabled. */
        void unbindInput();
        void createImeSession(IAccessibilityInputMethodSessionCallback callback);
        /** This is called when an app starts input or when the service is enabled. */
        void startInput(@Nullable InputConnection inputConnection,
                @NonNull EditorInfo editorInfo, boolean restarting,
                @NonNull IBinder startInputToken);
        void startInput(@Nullable RemoteAccessibilityInputConnection inputConnection,
                @NonNull EditorInfo editorInfo, boolean restarting);
    }

    /**
@@ -2740,42 +2725,20 @@ public abstract class AccessibilityService extends Service {
            }

            @Override
            public void createImeSession(IInputSessionWithIdCallback callback) {
            public void createImeSession(IAccessibilityInputMethodSessionCallback callback) {
                if (mInputMethod != null) {
                    mInputMethod.createImeSession(callback);
                }
            }

            @Override
            public void setImeSessionEnabled(InputMethodSession session, boolean enabled) {
                if (mInputMethod != null) {
                    mInputMethod.setImeSessionEnabled(session, enabled);
                }
            }

            @Override
            public void bindInput(InputBinding binding) {
                if (mInputMethod != null) {
                    mInputMethod.bindInput(binding);
                }
            }

            @Override
            public void unbindInput() {
                if (mInputMethod != null) {
                    mInputMethod.unbindInput();
                }
            }

            @Override
            public void startInput(@Nullable InputConnection inputConnection,
                    @NonNull EditorInfo editorInfo, boolean restarting,
                    @NonNull IBinder startInputToken) {
            public void startInput(@Nullable RemoteAccessibilityInputConnection connection,
                    @NonNull EditorInfo editorInfo, boolean restarting) {
                if (mInputMethod != null) {
                    if (restarting) {
                        mInputMethod.restartInput(inputConnection, editorInfo);
                        mInputMethod.restartInput(connection, editorInfo);
                    } else {
                        mInputMethod.startInput(inputConnection, editorInfo);
                        mInputMethod.startInput(connection, editorInfo);
                    }
                }
            }
@@ -2806,8 +2769,6 @@ public abstract class AccessibilityService extends Service {
        private static final int DO_ON_SYSTEM_ACTIONS_CHANGED = 14;
        private static final int DO_CREATE_IME_SESSION = 15;
        private static final int DO_SET_IME_SESSION_ENABLED = 16;
        private static final int DO_BIND_INPUT = 17;
        private static final int DO_UNBIND_INPUT = 18;
        private static final int DO_START_INPUT = 19;

        private final HandlerCaller mCaller;
@@ -2818,15 +2779,14 @@ public abstract class AccessibilityService extends Service {
        private int mConnectionId = AccessibilityInteractionClient.NO_ID;

        /**
         * This is not {@null} only between {@link #bindInput(InputBinding)} and
         * {@link #unbindInput()} so that {@link RemoteInputConnection} can query if
         * {@link #unbindInput()} has already been called or not, mainly to avoid unnecessary
         * blocking operations.
         * This is not {@code null} only between {@link #bindInput()} and {@link #unbindInput()} so
         * that {@link RemoteAccessibilityInputConnection} can query if {@link #unbindInput()} has
         * already been called or not, mainly to avoid unnecessary blocking operations.
         *
         * <p>This field must be set and cleared only from the binder thread(s), where the system
         * guarantees that {@link #bindInput(InputBinding)},
         * {@link #startInput(IBinder, IInputContext, EditorInfo, boolean)}, and
         * {@link #unbindInput()} are called with the same order as the original calls
         * guarantees that {@link #bindInput()},
         * {@link #startInput(IRemoteAccessibilityInputConnection, EditorInfo, boolean)},
         * and {@link #unbindInput()} are called with the same order as the original calls
         * in {@link com.android.server.inputmethod.InputMethodManagerService}.
         * See {@link IBinder#FLAG_ONEWAY} for detailed semantics.</p>
         */
@@ -2927,7 +2887,7 @@ public abstract class AccessibilityService extends Service {
        }

        /** This is called when an app requests ime sessions or when the service is enabled. */
        public void createImeSession(IInputSessionWithIdCallback callback) {
        public void createImeSession(IAccessibilityInputMethodSessionCallback callback) {
            final Message message = mCaller.obtainMessageO(DO_CREATE_IME_SESSION, callback);
            mCaller.sendMessage(message);
        }
@@ -2936,10 +2896,11 @@ public abstract class AccessibilityService extends Service {
         * This is called when InputMethodManagerService requests to set the session enabled or
         * disabled
         */
        public void setImeSessionEnabled(IInputMethodSession session, boolean enabled) {
        public void setImeSessionEnabled(IAccessibilityInputMethodSession session,
                boolean enabled) {
            try {
                InputMethodSession ls = ((IInputMethodSessionWrapper)
                        session).getInternalInputMethodSession();
                AccessibilityInputMethodSession ls =
                        ((AccessibilityInputMethodSessionWrapper) session).getSession();
                if (ls == null) {
                    Log.w(LOG_TAG, "Session is already finished: " + session);
                    return;
@@ -2952,17 +2913,11 @@ public abstract class AccessibilityService extends Service {
        }

        /** This is called when an app binds input or when the service is enabled. */
        public void bindInput(InputBinding binding) {
        public void bindInput() {
            if (mCancellationGroup != null) {
                Log.e(LOG_TAG, "bindInput must be paired with unbindInput.");
            }
            mCancellationGroup = new CancellationGroup();
            InputConnection ic = new RemoteInputConnection(new WeakReference<>(() -> mContext),
                    IInputContext.Stub.asInterface(binding.getConnectionToken()),
                    mCancellationGroup);
            InputBinding nu = new InputBinding(ic, binding);
            final Message message = mCaller.obtainMessageO(DO_BIND_INPUT, nu);
            mCaller.sendMessage(message);
        }

        /** This is called when an app unbinds input or when the service is disabled. */
@@ -2974,18 +2929,17 @@ public abstract class AccessibilityService extends Service {
            } else {
                Log.e(LOG_TAG, "unbindInput must be paired with bindInput.");
            }
            mCaller.sendMessage(mCaller.obtainMessage(DO_UNBIND_INPUT));
        }

        /** This is called when an app starts input or when the service is enabled. */
        public void startInput(IBinder startInputToken, IInputContext inputContext,
        public void startInput(IRemoteAccessibilityInputConnection connection,
                EditorInfo editorInfo, boolean restarting) {
            if (mCancellationGroup == null) {
                Log.e(LOG_TAG, "startInput must be called after bindInput.");
                mCancellationGroup = new CancellationGroup();
            }
            final Message message = mCaller.obtainMessageOOOOII(DO_START_INPUT, startInputToken,
                    inputContext, editorInfo, mCancellationGroup, restarting ? 1 : 0,
            final Message message = mCaller.obtainMessageOOOOII(DO_START_INPUT, null /* unused */,
                    connection, editorInfo, mCancellationGroup, restarting ? 1 : 0,
                    0 /* unused */);
            mCaller.sendMessage(message);
        }
@@ -3157,44 +3111,33 @@ public abstract class AccessibilityService extends Service {
                }
                case DO_CREATE_IME_SESSION: {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                        IInputSessionWithIdCallback callback =
                                (IInputSessionWithIdCallback) message.obj;
                        IAccessibilityInputMethodSessionCallback callback =
                                (IAccessibilityInputMethodSessionCallback) message.obj;
                        mCallback.createImeSession(callback);
                    }
                    return;
                }
                case DO_SET_IME_SESSION_ENABLED: {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                        mCallback.setImeSessionEnabled((InputMethodSession) message.obj,
                                message.arg1 != 0);
                    }
                    return;
                }
                case DO_BIND_INPUT: {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                        mCallback.bindInput((InputBinding) message.obj);
                    }
                    return;
                }
                case DO_UNBIND_INPUT: {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                        mCallback.unbindInput();
                        AccessibilityInputMethodSession session =
                                (AccessibilityInputMethodSession) message.obj;
                        session.setEnabled(message.arg1 != 0);
                    }
                    return;
                }
                case DO_START_INPUT: {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                        final SomeArgs args = (SomeArgs) message.obj;
                        final IBinder startInputToken = (IBinder) args.arg1;
                        final IInputContext inputContext = (IInputContext) args.arg2;
                        final IRemoteAccessibilityInputConnection connection =
                                (IRemoteAccessibilityInputConnection) args.arg2;
                        final EditorInfo info = (EditorInfo) args.arg3;
                        final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
                        final boolean restarting = args.argi5 == 1;
                        final InputConnection ic = inputContext != null
                                ? new RemoteInputConnection(new WeakReference<>(() -> mContext),
                                inputContext, cancellationGroup) : null;
                        final RemoteAccessibilityInputConnection ic = connection == null ? null
                                : new RemoteAccessibilityInputConnection(
                                        connection, cancellationGroup);
                        info.makeCompatible(mContext.getApplicationInfo().targetSdkVersion);
                        mCallback.startInput(ic, info, restarting, startInputToken);
                        mCallback.startInput(ic, info, restarting);
                        args.recycle();
                    }
                    return;
+8 −9
Original line number Diff line number Diff line
@@ -25,10 +25,9 @@ import android.accessibilityservice.MagnificationConfig;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.IInputSessionWithIdCallback;
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;

/**
 * Top-level interface to an accessibility service component.
@@ -69,14 +68,14 @@ import com.android.internal.view.IInputSessionWithIdCallback;

    void onSystemActionsChanged();

    void createImeSession(IInputSessionWithIdCallback callback);
    void createImeSession(in IAccessibilityInputMethodSessionCallback callback);

    void setImeSessionEnabled(IInputMethodSession session, boolean enabled);
    void setImeSessionEnabled(in IAccessibilityInputMethodSession session, boolean enabled);

    void bindInput(in InputBinding binding);
    void bindInput();

    void unbindInput();

    void startInput(in IBinder startInputToken, in IInputContext inputContext,
                in EditorInfo editorInfo, boolean restarting);
    void startInput(in IRemoteAccessibilityInputConnection connection, in EditorInfo editorInfo,
            boolean restarting);
}
+35 −140

File changed.

Preview size limit exceeded, changes collapsed.

Loading