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 Original line 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 Original line 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 Original line Diff line number Diff line
@@ -40,8 +40,6 @@ import android.graphics.ParcelableColorSpace;
import android.graphics.Region;
import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager;
import android.inputmethodservice.IInputMethodSessionWrapper;
import android.inputmethodservice.RemoteInputConnection;
import android.os.Build;
import android.os.Build;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler;
@@ -68,22 +66,19 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.inputmethod.EditorInfo;
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.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.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
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.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.concurrent.Executor;
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. */
        /** This is called when the system action list is changed. */
        void onSystemActionsChanged();
        void onSystemActionsChanged();
        /** This is called when an app requests ime sessions or when the service is enabled. */
        /** This is called when an app requests ime sessions or when the service is enabled. */
        void createImeSession(IInputSessionWithIdCallback callback);
        void createImeSession(IAccessibilityInputMethodSessionCallback 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();
        /** This is called when an app starts input or when the service is enabled. */
        /** This is called when an app starts input or when the service is enabled. */
        void startInput(@Nullable InputConnection inputConnection,
        void startInput(@Nullable RemoteAccessibilityInputConnection inputConnection,
                @NonNull EditorInfo editorInfo, boolean restarting,
                @NonNull EditorInfo editorInfo, boolean restarting);
                @NonNull IBinder startInputToken);
    }
    }


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


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


            @Override
            @Override
            public void setImeSessionEnabled(InputMethodSession session, boolean enabled) {
            public void startInput(@Nullable RemoteAccessibilityInputConnection connection,
                if (mInputMethod != null) {
                    @NonNull EditorInfo editorInfo, boolean restarting) {
                    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) {
                if (mInputMethod != null) {
                if (mInputMethod != null) {
                    if (restarting) {
                    if (restarting) {
                        mInputMethod.restartInput(inputConnection, editorInfo);
                        mInputMethod.restartInput(connection, editorInfo);
                    } else {
                    } 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_ON_SYSTEM_ACTIONS_CHANGED = 14;
        private static final int DO_CREATE_IME_SESSION = 15;
        private static final int DO_CREATE_IME_SESSION = 15;
        private static final int DO_SET_IME_SESSION_ENABLED = 16;
        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 static final int DO_START_INPUT = 19;


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


        /**
        /**
         * This is not {@null} only between {@link #bindInput(InputBinding)} and
         * This is not {@code null} only between {@link #bindInput()} and {@link #unbindInput()} so
         * {@link #unbindInput()} so that {@link RemoteInputConnection} can query if
         * that {@link RemoteAccessibilityInputConnection} can query if {@link #unbindInput()} has
         * {@link #unbindInput()} has already been called or not, mainly to avoid unnecessary
         * already been called or not, mainly to avoid unnecessary blocking operations.
         * blocking operations.
         *
         *
         * <p>This field must be set and cleared only from the binder thread(s), where the system
         * <p>This field must be set and cleared only from the binder thread(s), where the system
         * guarantees that {@link #bindInput(InputBinding)},
         * guarantees that {@link #bindInput()},
         * {@link #startInput(IBinder, IInputContext, EditorInfo, boolean)}, and
         * {@link #startInput(IRemoteAccessibilityInputConnection, EditorInfo, boolean)},
         * {@link #unbindInput()} are called with the same order as the original calls
         * and {@link #unbindInput()} are called with the same order as the original calls
         * in {@link com.android.server.inputmethod.InputMethodManagerService}.
         * in {@link com.android.server.inputmethod.InputMethodManagerService}.
         * See {@link IBinder#FLAG_ONEWAY} for detailed semantics.</p>
         * 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. */
        /** 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);
            final Message message = mCaller.obtainMessageO(DO_CREATE_IME_SESSION, callback);
            mCaller.sendMessage(message);
            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
         * This is called when InputMethodManagerService requests to set the session enabled or
         * disabled
         * disabled
         */
         */
        public void setImeSessionEnabled(IInputMethodSession session, boolean enabled) {
        public void setImeSessionEnabled(IAccessibilityInputMethodSession session,
                boolean enabled) {
            try {
            try {
                InputMethodSession ls = ((IInputMethodSessionWrapper)
                AccessibilityInputMethodSession ls =
                        session).getInternalInputMethodSession();
                        ((AccessibilityInputMethodSessionWrapper) session).getSession();
                if (ls == null) {
                if (ls == null) {
                    Log.w(LOG_TAG, "Session is already finished: " + session);
                    Log.w(LOG_TAG, "Session is already finished: " + session);
                    return;
                    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. */
        /** 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) {
            if (mCancellationGroup != null) {
                Log.e(LOG_TAG, "bindInput must be paired with unbindInput.");
                Log.e(LOG_TAG, "bindInput must be paired with unbindInput.");
            }
            }
            mCancellationGroup = new CancellationGroup();
            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. */
        /** 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 {
            } else {
                Log.e(LOG_TAG, "unbindInput must be paired with bindInput.");
                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. */
        /** 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) {
                EditorInfo editorInfo, boolean restarting) {
            if (mCancellationGroup == null) {
            if (mCancellationGroup == null) {
                Log.e(LOG_TAG, "startInput must be called after bindInput.");
                Log.e(LOG_TAG, "startInput must be called after bindInput.");
                mCancellationGroup = new CancellationGroup();
                mCancellationGroup = new CancellationGroup();
            }
            }
            final Message message = mCaller.obtainMessageOOOOII(DO_START_INPUT, startInputToken,
            final Message message = mCaller.obtainMessageOOOOII(DO_START_INPUT, null /* unused */,
                    inputContext, editorInfo, mCancellationGroup, restarting ? 1 : 0,
                    connection, editorInfo, mCancellationGroup, restarting ? 1 : 0,
                    0 /* unused */);
                    0 /* unused */);
            mCaller.sendMessage(message);
            mCaller.sendMessage(message);
        }
        }
@@ -3157,44 +3111,33 @@ public abstract class AccessibilityService extends Service {
                }
                }
                case DO_CREATE_IME_SESSION: {
                case DO_CREATE_IME_SESSION: {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                        IInputSessionWithIdCallback callback =
                        IAccessibilityInputMethodSessionCallback callback =
                                (IInputSessionWithIdCallback) message.obj;
                                (IAccessibilityInputMethodSessionCallback) message.obj;
                        mCallback.createImeSession(callback);
                        mCallback.createImeSession(callback);
                    }
                    }
                    return;
                    return;
                }
                }
                case DO_SET_IME_SESSION_ENABLED: {
                case DO_SET_IME_SESSION_ENABLED: {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                        mCallback.setImeSessionEnabled((InputMethodSession) message.obj,
                        AccessibilityInputMethodSession session =
                                message.arg1 != 0);
                                (AccessibilityInputMethodSession) message.obj;
                    }
                        session.setEnabled(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();
                    }
                    }
                    return;
                    return;
                }
                }
                case DO_START_INPUT: {
                case DO_START_INPUT: {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
                        final SomeArgs args = (SomeArgs) message.obj;
                        final SomeArgs args = (SomeArgs) message.obj;
                        final IBinder startInputToken = (IBinder) args.arg1;
                        final IRemoteAccessibilityInputConnection connection =
                        final IInputContext inputContext = (IInputContext) args.arg2;
                                (IRemoteAccessibilityInputConnection) args.arg2;
                        final EditorInfo info = (EditorInfo) args.arg3;
                        final EditorInfo info = (EditorInfo) args.arg3;
                        final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
                        final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
                        final boolean restarting = args.argi5 == 1;
                        final boolean restarting = args.argi5 == 1;
                        final InputConnection ic = inputContext != null
                        final RemoteAccessibilityInputConnection ic = connection == null ? null
                                ? new RemoteInputConnection(new WeakReference<>(() -> mContext),
                                : new RemoteAccessibilityInputConnection(
                                inputContext, cancellationGroup) : null;
                                        connection, cancellationGroup);
                        info.makeCompatible(mContext.getApplicationInfo().targetSdkVersion);
                        info.makeCompatible(mContext.getApplicationInfo().targetSdkVersion);
                        mCallback.startInput(ic, info, restarting, startInputToken);
                        mCallback.startInput(ic, info, restarting);
                        args.recycle();
                        args.recycle();
                    }
                    }
                    return;
                    return;
+8 −9
Original line number Original line Diff line number Diff line
@@ -25,10 +25,9 @@ import android.accessibilityservice.MagnificationConfig;
import android.view.KeyEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
import com.android.internal.view.IInputContext;
import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
import com.android.internal.view.IInputMethodSession;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.view.IInputSessionWithIdCallback;


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


    void onSystemActionsChanged();
    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 unbindInput();


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

File changed.

Preview size limit exceeded, changes collapsed.

Loading