summaryrefslogtreecommitdiff
path: root/core/java/android/accessibilityservice/AccessibilityInputMethodSessionWrapper.java
diff options
context:
space:
mode:
authorYohei Yukawa <yukawa@google.com>2022-04-18 08:59:44 -0700
committerYohei Yukawa <yukawa@google.com>2022-04-18 08:59:44 -0700
commitc60176c1f315e10c95f3eec0019149d7b7932aa9 (patch)
tree8c8348bc4263f5fec9da0baf624d094e91ccf83e /core/java/android/accessibilityservice/AccessibilityInputMethodSessionWrapper.java
parent4008e21f0a9528bb2126d859ed6b6550f988c7c7 (diff)
Let A11yIME use its own IPC definitions
This is a follow up CL to our previuos CL [1], which enabled AccessibilityService to use a subset of InputConnection APIs. In that CL we have reused existing AIDL interfaces that were designed and maintained for IMEs for simplicity, where a non trivial amount of unnecessary IPC endpoints were included. From the security and maintainability viewpoints, however, exposing unnecessary IPC endpoints is discouraged in general. To address such concerns this CL introduces a set of dedicated IPC definitions for A11yIME so that we do not need to reuse IPCs for IMEs. This CL also stops passing InputBinding object to A11yIME process as it contains IInputContext Binder Proxy, which can still be used to directly invoke fallback InputConnection. This is doable now because A11yIME no longer relies on fallback InputConnection [2]. This CL is should not have any observable changes in the semantics. End-to-end CTS tests guarantee that everything is still working as intended now and in the future. [1]: Ia651a811093a939d00c081be1961e24ed3ad0356 fb17e5ae7a9e1a095d114d8dde76f14578b6c233 [2]: I2af3cd50444d8ddf25aa0f6479238156914e6fff dc635efb687ac04045f2756b02c5ca2435762956 Fix: 215633021 Fix: 215636776 Test: atest CtsInputMethodTestCases:AccessibilityInputMethodTest Test: atest CtsAccessibilityServiceTestCases:AccessibilityInputConnectionTest Test: atest CtsAccessibilityServiceTestCases:AccessibilityImeTest Change-Id: I5ff2e804cbcf90828370a0612ff54111130bdff4
Diffstat (limited to 'core/java/android/accessibilityservice/AccessibilityInputMethodSessionWrapper.java')
-rw-r--r--core/java/android/accessibilityservice/AccessibilityInputMethodSessionWrapper.java116
1 files changed, 116 insertions, 0 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityInputMethodSessionWrapper.java b/core/java/android/accessibilityservice/AccessibilityInputMethodSessionWrapper.java
new file mode 100644
index 000000000000..3252ab23486f
--- /dev/null
+++ b/core/java/android/accessibilityservice/AccessibilityInputMethodSessionWrapper.java
@@ -0,0 +1,116 @@
+/*
+ * 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);
+ }
+ }
+}