Merge "Let A11yIME use its own IPC definitions" into tm-dev
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -18,36 +18,23 @@ package android.accessibilityservice;
|
||||
|
||||
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Rect;
|
||||
import android.inputmethodservice.IInputMethodSessionWrapper;
|
||||
import android.inputmethodservice.RemoteInputConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.Trace;
|
||||
import android.util.Log;
|
||||
import android.view.KeyCharacterMap;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.inputmethod.CompletionInfo;
|
||||
import android.view.inputmethod.CursorAnchorInfo;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.ExtractedText;
|
||||
import android.view.inputmethod.InputBinding;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.view.inputmethod.InputMethodSession;
|
||||
import android.view.inputmethod.SurroundingText;
|
||||
import android.view.inputmethod.TextAttribute;
|
||||
|
||||
import com.android.internal.view.IInputContext;
|
||||
import com.android.internal.view.IInputSessionWithIdCallback;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
import com.android.internal.inputmethod.RemoteAccessibilityInputConnection;
|
||||
|
||||
/**
|
||||
* This class provides input method APIs. Some public methods such as
|
||||
@@ -61,9 +48,8 @@ public class InputMethod {
|
||||
private static final String LOG_TAG = "A11yInputMethod";
|
||||
|
||||
private final AccessibilityService mService;
|
||||
private InputBinding mInputBinding;
|
||||
private boolean mInputStarted;
|
||||
private InputConnection mStartedInputConnection;
|
||||
private RemoteAccessibilityInputConnection mStartedInputConnection;
|
||||
private EditorInfo mInputEditorInfo;
|
||||
|
||||
/**
|
||||
@@ -131,9 +117,7 @@ public class InputMethod {
|
||||
* to perform whatever behavior you would like.
|
||||
*/
|
||||
public void onFinishInput() {
|
||||
if (mStartedInputConnection != null) {
|
||||
mStartedInputConnection.finishComposingText();
|
||||
}
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,41 +136,26 @@ public class InputMethod {
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
final void createImeSession(IInputSessionWithIdCallback callback) {
|
||||
InputMethodSession session = onCreateInputMethodSessionInterface();
|
||||
final void createImeSession(IAccessibilityInputMethodSessionCallback callback) {
|
||||
final AccessibilityInputMethodSessionWrapper wrapper =
|
||||
new AccessibilityInputMethodSessionWrapper(mService.getMainLooper(),
|
||||
new SessionImpl());
|
||||
try {
|
||||
IInputMethodSessionWrapper wrap =
|
||||
new IInputMethodSessionWrapper(mService, session, null);
|
||||
callback.sessionCreated(wrap, mService.getConnectionId());
|
||||
callback.sessionCreated(wrapper, mService.getConnectionId());
|
||||
} catch (RemoteException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
final void setImeSessionEnabled(@NonNull InputMethodSession session, boolean enabled) {
|
||||
((InputMethodSessionForAccessibility) session).setEnabled(enabled);
|
||||
}
|
||||
|
||||
final void bindInput(@NonNull InputBinding binding) {
|
||||
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AccessibilityService.bindInput");
|
||||
mInputBinding = binding;
|
||||
Log.v(LOG_TAG, "bindInput(): binding=" + binding);
|
||||
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
||||
}
|
||||
|
||||
final void unbindInput() {
|
||||
Log.v(LOG_TAG, "unbindInput(): binding=" + mInputBinding);
|
||||
// Unbind input is per process per display.
|
||||
mInputBinding = null;
|
||||
}
|
||||
|
||||
final void startInput(@Nullable InputConnection ic, @NonNull EditorInfo attribute) {
|
||||
final void startInput(@Nullable RemoteAccessibilityInputConnection ic,
|
||||
@NonNull EditorInfo attribute) {
|
||||
Log.v(LOG_TAG, "startInput(): editor=" + attribute);
|
||||
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AccessibilityService.startInput");
|
||||
doStartInput(ic, attribute, false /* restarting */);
|
||||
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
||||
}
|
||||
|
||||
final void restartInput(@Nullable InputConnection ic, @NonNull EditorInfo attribute) {
|
||||
final void restartInput(@Nullable RemoteAccessibilityInputConnection ic,
|
||||
@NonNull EditorInfo attribute) {
|
||||
Log.v(LOG_TAG, "restartInput(): editor=" + attribute);
|
||||
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AccessibilityService.restartInput");
|
||||
doStartInput(ic, attribute, true /* restarting */);
|
||||
@@ -194,7 +163,8 @@ public class InputMethod {
|
||||
}
|
||||
|
||||
|
||||
final void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
|
||||
final void doStartInput(RemoteAccessibilityInputConnection ic, EditorInfo attribute,
|
||||
boolean restarting) {
|
||||
if ((ic == null || !restarting) && mInputStarted) {
|
||||
doFinishInput();
|
||||
if (ic == null) {
|
||||
@@ -220,17 +190,13 @@ public class InputMethod {
|
||||
mInputEditorInfo = null;
|
||||
}
|
||||
|
||||
private InputMethodSession onCreateInputMethodSessionInterface() {
|
||||
return new InputMethodSessionForAccessibility();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class provides the allowed list of {@link InputConnection} APIs for
|
||||
* accessibility services.
|
||||
*/
|
||||
public final class AccessibilityInputConnection {
|
||||
private InputConnection mIc;
|
||||
AccessibilityInputConnection(InputConnection ic) {
|
||||
private final RemoteAccessibilityInputConnection mIc;
|
||||
AccessibilityInputConnection(RemoteAccessibilityInputConnection ic) {
|
||||
this.mIc = ic;
|
||||
}
|
||||
|
||||
@@ -249,7 +215,7 @@ public class InputMethod {
|
||||
* int, int)} on the current accessibility service after the batch input is over.
|
||||
* <strong>Editor authors</strong>, for this to happen you need to
|
||||
* make the changes known to the accessibility service by calling
|
||||
* {@link InputMethodManager#updateSelection(View, int, int, int, int)},
|
||||
* {@link InputMethodManager#updateSelection(android.view.View, int, int, int, int)},
|
||||
* but be careful to wait until the batch edit is over if one is
|
||||
* in progress.</p>
|
||||
*
|
||||
@@ -282,7 +248,7 @@ public class InputMethod {
|
||||
* int,int, int)} on the current IME after the batch input is over.
|
||||
* <strong>Editor authors</strong>, for this to happen you need to
|
||||
* make the changes known to the input method by calling
|
||||
* {@link InputMethodManager#updateSelection(View, int, int, int, int)},
|
||||
* {@link InputMethodManager#updateSelection(android.view.View, int, int, int, int)},
|
||||
* but be careful to wait until the batch edit is over if one is
|
||||
* in progress.</p>
|
||||
*
|
||||
@@ -367,9 +333,8 @@ public class InputMethod {
|
||||
* delete only half of a surrogate pair. Also take care not to
|
||||
* delete more characters than are in the editor, as that may have
|
||||
* ill effects on the application. Calling this method will cause
|
||||
* the editor to call
|
||||
* {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
|
||||
* int, int)} on your service after the batch input is over.</p>
|
||||
* the editor to call {@link InputMethod#onUpdateSelection(int, int, int, int, int, int)}
|
||||
* on your service after the batch input is over.</p>
|
||||
*
|
||||
* <p><strong>Editor authors:</strong> please be careful of race
|
||||
* conditions in implementing this call. An IME can make a change
|
||||
@@ -381,7 +346,7 @@ public class InputMethod {
|
||||
* indices to the size of the contents to avoid crashes. Since
|
||||
* this changes the contents of the editor, you need to make the
|
||||
* changes known to the input method by calling
|
||||
* {@link InputMethodManager#updateSelection(View, int, int, int, int)},
|
||||
* {@link InputMethodManager#updateSelection(android.view.View, int, int, int, int)},
|
||||
* but be careful to wait until the batch edit is over if one is
|
||||
* in progress.</p>
|
||||
*
|
||||
@@ -522,12 +487,13 @@ public class InputMethod {
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete implementation of InputMethodSession that provides all of the standard behavior
|
||||
* for an input method session.
|
||||
* Concrete implementation of {@link AccessibilityInputMethodSession} that provides all of the
|
||||
* standard behavior for an A11y input method session.
|
||||
*/
|
||||
private final class InputMethodSessionForAccessibility implements InputMethodSession {
|
||||
private final class SessionImpl implements AccessibilityInputMethodSession {
|
||||
boolean mEnabled = true;
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
mEnabled = enabled;
|
||||
}
|
||||
@@ -549,86 +515,15 @@ public class InputMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void viewClicked(boolean focusChanged) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCursor(@NonNull Rect newCursor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayCompletions(
|
||||
@SuppressLint("ArrayReturn") @NonNull CompletionInfo[] completions) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExtractedText(int token, @NonNull ExtractedText text) {
|
||||
}
|
||||
|
||||
public void dispatchKeyEvent(int seq, @NonNull KeyEvent event,
|
||||
@NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchKeyEvent(int seq, @NonNull KeyEvent event,
|
||||
@NonNull EventCallback callback) {
|
||||
}
|
||||
|
||||
public void dispatchTrackballEvent(int seq, @NonNull MotionEvent event,
|
||||
@NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchTrackballEvent(int seq, @NonNull MotionEvent event,
|
||||
@NonNull EventCallback callback) {
|
||||
}
|
||||
|
||||
public void dispatchGenericMotionEvent(int seq, @NonNull MotionEvent event,
|
||||
@NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchGenericMotionEvent(int seq, @NonNull MotionEvent event,
|
||||
@NonNull EventCallback callback) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appPrivateCommand(@NonNull String action, @NonNull Bundle data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggleSoftInput(int showFlags, int hideFlags) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCursorAnchorInfo(@NonNull CursorAnchorInfo cursorAnchorInfo) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyImeHidden() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeImeSurface() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void invalidateInputInternal(EditorInfo editorInfo, IInputContext inputContext,
|
||||
int sessionId) {
|
||||
if (mStartedInputConnection instanceof RemoteInputConnection) {
|
||||
final RemoteInputConnection ric =
|
||||
(RemoteInputConnection) mStartedInputConnection;
|
||||
if (!ric.isSameConnection(inputContext)) {
|
||||
// This is not an error, and can be safely ignored.
|
||||
return;
|
||||
}
|
||||
editorInfo.makeCompatible(
|
||||
mService.getApplicationInfo().targetSdkVersion);
|
||||
restartInput(new RemoteInputConnection(ric, sessionId), editorInfo);
|
||||
public void invalidateInput(EditorInfo editorInfo,
|
||||
IRemoteAccessibilityInputConnection connection, int sessionId) {
|
||||
if (!mStartedInputConnection.isSameConnection(connection)) {
|
||||
// This is not an error, and can be safely ignored.
|
||||
return;
|
||||
}
|
||||
editorInfo.makeCompatible(mService.getApplicationInfo().targetSdkVersion);
|
||||
restartInput(new RemoteAccessibilityInputConnection(mStartedInputConnection, sessionId),
|
||||
editorInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,13 +64,11 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityWindowInfo;
|
||||
import android.view.accessibility.IAccessibilityInteractionConnection;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputBinding;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodSession;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
|
||||
import com.android.internal.inputmethod.RemoteAccessibilityInputConnection;
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
import com.android.internal.view.IInputSessionWithIdCallback;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
@@ -1574,26 +1572,14 @@ public final class UiAutomation {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createImeSession(IInputSessionWithIdCallback callback) {
|
||||
public void createImeSession(IAccessibilityInputMethodSessionCallback callback) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImeSessionEnabled(InputMethodSession session, boolean enabled) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindInput(InputBinding binding) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindInput() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startInput(@Nullable InputConnection inputConnection,
|
||||
@NonNull EditorInfo editorInfo, boolean restarting,
|
||||
@NonNull IBinder startInputToken) {
|
||||
public void startInput(
|
||||
@Nullable RemoteAccessibilityInputConnection inputConnection,
|
||||
@NonNull EditorInfo editorInfo, boolean restarting) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -41,9 +41,7 @@ import com.android.internal.os.SomeArgs;
|
||||
import com.android.internal.view.IInputContext;
|
||||
import com.android.internal.view.IInputMethodSession;
|
||||
|
||||
/** @hide */
|
||||
// TODO(b/215636776): move IInputMethodSessionWrapper to proper package
|
||||
public class IInputMethodSessionWrapper extends IInputMethodSession.Stub
|
||||
class IInputMethodSessionWrapper extends IInputMethodSession.Stub
|
||||
implements HandlerCaller.Callback {
|
||||
private static final String TAG = "InputMethodWrapper";
|
||||
|
||||
|
||||
@@ -32,11 +32,8 @@ import java.io.PrintWriter;
|
||||
* framework classes for internal use.
|
||||
*
|
||||
* <p>CAVEATS: {@link AbstractInputMethodService} does not support all the methods here.</p>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO(b/215636776): move InputMethodServiceInternal to proper package
|
||||
public interface InputMethodServiceInternal {
|
||||
interface InputMethodServiceInternal {
|
||||
/**
|
||||
* @return {@link Context} associated with the service.
|
||||
*/
|
||||
|
||||
@@ -53,11 +53,8 @@ import java.util.concurrent.CompletableFuture;
|
||||
*
|
||||
* <p>See also {@link IInputContext} for the actual {@link android.os.Binder} IPC protocols under
|
||||
* the hood.</p>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO(b/215636776): move RemoteInputConnection to proper package
|
||||
public final class RemoteInputConnection implements InputConnection {
|
||||
final class RemoteInputConnection implements InputConnection {
|
||||
private static final String TAG = "RemoteInputConnection";
|
||||
|
||||
private static final int MAX_WAIT_TIME_MILLIS = 2000;
|
||||
@@ -98,7 +95,7 @@ public final class RemoteInputConnection implements InputConnection {
|
||||
@NonNull
|
||||
private final CancellationGroup mCancellationGroup;
|
||||
|
||||
public RemoteInputConnection(
|
||||
RemoteInputConnection(
|
||||
@NonNull WeakReference<InputMethodServiceInternal> inputMethodService,
|
||||
IInputContext inputContext, @NonNull CancellationGroup cancellationGroup) {
|
||||
mImsInternal = new InputMethodServiceInternalHolder(inputMethodService);
|
||||
@@ -111,7 +108,7 @@ public final class RemoteInputConnection implements InputConnection {
|
||||
return mInvoker.isSameConnection(inputContext);
|
||||
}
|
||||
|
||||
public RemoteInputConnection(@NonNull RemoteInputConnection original, int sessionId) {
|
||||
RemoteInputConnection(@NonNull RemoteInputConnection original, int sessionId) {
|
||||
mImsInternal = original.mImsInternal;
|
||||
mInvoker = original.mInvoker.cloneWithSessionId(sessionId);
|
||||
mCancellationGroup = original.mCancellationGroup;
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.view.inputmethod;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
|
||||
final class IAccessibilityInputMethodSessionInvoker {
|
||||
private static final String TAG = "IAccessibilityInputMethodSessionInvoker";
|
||||
|
||||
/**
|
||||
* The actual instance of the method to make calls on it.
|
||||
*/
|
||||
@NonNull
|
||||
private final IAccessibilityInputMethodSession mSession;
|
||||
|
||||
private IAccessibilityInputMethodSessionInvoker(
|
||||
@NonNull IAccessibilityInputMethodSession session) {
|
||||
mSession = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link IAccessibilityInputMethodSessionInvoker} instance if applicable.
|
||||
*
|
||||
* @param session {@link IAccessibilityInputMethodSession} object to be wrapped.
|
||||
* @return an instance of {@link IAccessibilityInputMethodSessionInvoker} if
|
||||
* {@code inputMethodSession} is not {@code null}. {@code null} otherwise.
|
||||
*/
|
||||
@Nullable
|
||||
public static IAccessibilityInputMethodSessionInvoker createOrNull(
|
||||
@NonNull IAccessibilityInputMethodSession session) {
|
||||
return session == null ? null : new IAccessibilityInputMethodSessionInvoker(session);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
void finishInput() {
|
||||
try {
|
||||
mSession.finishInput();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "A11yIME died", e);
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
void updateSelection(int oldSelStart, int oldSelEnd, int selStart, int selEnd,
|
||||
int candidatesStart, int candidatesEnd) {
|
||||
try {
|
||||
mSession.updateSelection(
|
||||
oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "A11yIME died", e);
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
void invalidateInput(EditorInfo editorInfo, IRemoteAccessibilityInputConnection connection,
|
||||
int sessionId) {
|
||||
try {
|
||||
mSession.invalidateInput(editorInfo, connection, sessionId);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "A11yIME died", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,6 +93,7 @@ import android.view.autofill.AutofillManager;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.inputmethod.DirectBootAwareness;
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
import com.android.internal.inputmethod.ImeTracing;
|
||||
import com.android.internal.inputmethod.InputBindResult;
|
||||
import com.android.internal.inputmethod.InputMethodDebug;
|
||||
@@ -506,8 +507,8 @@ public final class InputMethodManager {
|
||||
*/
|
||||
@Nullable
|
||||
@GuardedBy("mH")
|
||||
private final SparseArray<InputMethodSessionWrapper> mAccessibilityInputMethodSession =
|
||||
new SparseArray<>();
|
||||
private final SparseArray<IAccessibilityInputMethodSessionInvoker>
|
||||
mAccessibilityInputMethodSession = new SparseArray<>();
|
||||
|
||||
InputChannel mCurChannel;
|
||||
ImeInputEventSender mCurSender;
|
||||
@@ -669,7 +670,8 @@ public final class InputMethodManager {
|
||||
if (mCurrentInputMethodSession != null) {
|
||||
mCurrentInputMethodSession.finishInput();
|
||||
}
|
||||
forAccessibilitySessions(InputMethodSessionWrapper::finishInput);
|
||||
forAccessibilitySessionsLocked(
|
||||
IAccessibilityInputMethodSessionInvoker::finishInput);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,7 +732,7 @@ public final class InputMethodManager {
|
||||
focusedView.getWindowToken(), startInputFlags, softInputMode,
|
||||
windowFlags,
|
||||
null,
|
||||
null,
|
||||
null, null,
|
||||
mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
@@ -963,13 +965,13 @@ public final class InputMethodManager {
|
||||
// we send a notification so that the a11y service knows the session is
|
||||
// registered and update the a11y service with the current cursor positions.
|
||||
if (res.accessibilitySessions != null) {
|
||||
InputMethodSessionWrapper wrapper =
|
||||
InputMethodSessionWrapper.createOrNull(
|
||||
IAccessibilityInputMethodSessionInvoker invoker =
|
||||
IAccessibilityInputMethodSessionInvoker.createOrNull(
|
||||
res.accessibilitySessions.get(id));
|
||||
if (wrapper != null) {
|
||||
mAccessibilityInputMethodSession.put(id, wrapper);
|
||||
if (invoker != null) {
|
||||
mAccessibilityInputMethodSession.put(id, invoker);
|
||||
if (mServedInputConnection != null) {
|
||||
wrapper.updateSelection(mInitialSelStart, mInitialSelEnd,
|
||||
invoker.updateSelection(mInitialSelStart, mInitialSelEnd,
|
||||
mCursorSelStart, mCursorSelEnd, mCursorCandStart,
|
||||
mCursorCandEnd);
|
||||
} else {
|
||||
@@ -978,9 +980,7 @@ public final class InputMethodManager {
|
||||
// binds before or after input starts, it may wonder if it binds
|
||||
// after input starts, why it doesn't receive a notification of
|
||||
// the current cursor positions.
|
||||
wrapper.updateSelection(-1, -1,
|
||||
-1, -1, -1,
|
||||
-1);
|
||||
invoker.updateSelection(-1, -1, -1, -1, -1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2148,8 +2148,10 @@ public final class InputMethodManager {
|
||||
editorInfo.setInitialSurroundingTextInternal(textSnapshot.getSurroundingText());
|
||||
mCurrentInputMethodSession.invalidateInput(editorInfo, mServedInputConnection,
|
||||
sessionId);
|
||||
forAccessibilitySessions(wrapper -> wrapper.invalidateInput(editorInfo,
|
||||
mServedInputConnection, sessionId));
|
||||
final IRemoteAccessibilityInputConnection accessibilityInputConnection =
|
||||
mServedInputConnection.asIRemoteAccessibilityInputConnection();
|
||||
forAccessibilitySessionsLocked(wrapper -> wrapper.invalidateInput(editorInfo,
|
||||
accessibilityInputConnection, sessionId));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2323,6 +2325,8 @@ public final class InputMethodManager {
|
||||
res = mService.startInputOrWindowGainedFocus(
|
||||
startInputReason, mClient, windowGainingFocus, startInputFlags,
|
||||
softInputMode, windowFlags, tba, servedInputConnection,
|
||||
servedInputConnection == null ? null
|
||||
: servedInputConnection.asIRemoteAccessibilityInputConnection(),
|
||||
view.getContext().getApplicationInfo().targetSdkVersion);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
@@ -2347,8 +2351,9 @@ public final class InputMethodManager {
|
||||
mAccessibilityInputMethodSession.clear();
|
||||
if (res.accessibilitySessions != null) {
|
||||
for (int i = 0; i < res.accessibilitySessions.size(); i++) {
|
||||
InputMethodSessionWrapper wrapper = InputMethodSessionWrapper.createOrNull(
|
||||
res.accessibilitySessions.valueAt(i));
|
||||
IAccessibilityInputMethodSessionInvoker wrapper =
|
||||
IAccessibilityInputMethodSessionInvoker.createOrNull(
|
||||
res.accessibilitySessions.valueAt(i));
|
||||
if (wrapper != null) {
|
||||
mAccessibilityInputMethodSession.append(
|
||||
res.accessibilitySessions.keyAt(i), wrapper);
|
||||
@@ -2598,7 +2603,7 @@ public final class InputMethodManager {
|
||||
mCursorCandEnd = candidatesEnd;
|
||||
mCurrentInputMethodSession.updateSelection(
|
||||
oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
|
||||
forAccessibilitySessions(wrapper -> wrapper.updateSelection(oldSelStart,
|
||||
forAccessibilitySessionsLocked(wrapper -> wrapper.updateSelection(oldSelStart,
|
||||
oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd));
|
||||
}
|
||||
}
|
||||
@@ -3658,7 +3663,8 @@ public final class InputMethodManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void forAccessibilitySessions(Consumer<InputMethodSessionWrapper> consumer) {
|
||||
private void forAccessibilitySessionsLocked(
|
||||
Consumer<IAccessibilityInputMethodSessionInvoker> consumer) {
|
||||
for (int i = 0; i < mAccessibilityInputMethodSession.size(); i++) {
|
||||
consumer.accept(mAccessibilityInputMethodSession.valueAt(i));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 com.android.internal.inputmethod;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.inputmethod.CompletionInfo;
|
||||
import android.view.inputmethod.CursorAnchorInfo;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.ExtractedText;
|
||||
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
import com.android.internal.view.IInputContext;
|
||||
|
||||
/**
|
||||
* Sub-interface of IInputMethodSession which is safe to give to A11y IME.
|
||||
*/
|
||||
oneway interface IAccessibilityInputMethodSession {
|
||||
void updateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd,
|
||||
int candidatesStart, int candidatesEnd);
|
||||
|
||||
void finishInput();
|
||||
|
||||
void finishSession();
|
||||
|
||||
void invalidateInput(in EditorInfo editorInfo,
|
||||
in IRemoteAccessibilityInputConnection connection, int sessionId);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
* 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.
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.view;
|
||||
package com.android.internal.inputmethod;
|
||||
|
||||
import com.android.internal.view.IInputMethodSession;
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
|
||||
|
||||
/**
|
||||
* Helper interface for IInputMethod to allow the input method to notify the client when a new
|
||||
* session has been created.
|
||||
*/
|
||||
oneway interface IInputSessionWithIdCallback {
|
||||
void sessionCreated(IInputMethodSession session, int id);
|
||||
}
|
||||
oneway interface IAccessibilityInputMethodSessionCallback {
|
||||
void sessionCreated(IAccessibilityInputMethodSession session, int id);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 com.android.internal.inputmethod;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.TextAttribute;
|
||||
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
import com.android.internal.inputmethod.InputConnectionCommandHeader;
|
||||
|
||||
/**
|
||||
* Interface from A11y IMEs to the application, allowing it to perform edits on the current input
|
||||
* field and other interactions with the application.
|
||||
*/
|
||||
oneway interface IRemoteAccessibilityInputConnection {
|
||||
void commitText(in InputConnectionCommandHeader header, CharSequence text,
|
||||
int newCursorPosition, in TextAttribute textAttribute);
|
||||
|
||||
void setSelection(in InputConnectionCommandHeader header, int start, int end);
|
||||
|
||||
void getSurroundingText(in InputConnectionCommandHeader header, int beforeLength,
|
||||
int afterLength, int flags, in AndroidFuture future /* T=SurroundingText */);
|
||||
|
||||
void deleteSurroundingText(in InputConnectionCommandHeader header, int beforeLength,
|
||||
int afterLength);
|
||||
|
||||
void sendKeyEvent(in InputConnectionCommandHeader header, in KeyEvent event);
|
||||
|
||||
void performEditorAction(in InputConnectionCommandHeader header, int actionCode);
|
||||
|
||||
void performContextMenuAction(in InputConnectionCommandHeader header, int id);
|
||||
|
||||
void getCursorCapsMode(in InputConnectionCommandHeader header, int reqModes,
|
||||
in AndroidFuture future /* T=Integer */);
|
||||
|
||||
void clearMetaKeyStates(in InputConnectionCommandHeader header, int states);
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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 com.android.internal.inputmethod;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.SurroundingText;
|
||||
import android.view.inputmethod.TextAttribute;
|
||||
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
final class IRemoteAccessibilityInputConnectionInvoker {
|
||||
@NonNull
|
||||
private final IRemoteAccessibilityInputConnection mConnection;
|
||||
private final int mSessionId;
|
||||
|
||||
private IRemoteAccessibilityInputConnectionInvoker(
|
||||
@NonNull IRemoteAccessibilityInputConnection inputContext, int sessionId) {
|
||||
mConnection = inputContext;
|
||||
mSessionId = sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link IRemoteAccessibilityInputConnectionInvoker} for the given
|
||||
* {@link IRemoteAccessibilityInputConnection}.
|
||||
*
|
||||
* @param connection {@link IRemoteAccessibilityInputConnection} to be wrapped.
|
||||
* @return A new instance of {@link IRemoteAccessibilityInputConnectionInvoker}.
|
||||
*/
|
||||
public static IRemoteAccessibilityInputConnectionInvoker create(
|
||||
@NonNull IRemoteAccessibilityInputConnection connection) {
|
||||
Objects.requireNonNull(connection);
|
||||
return new IRemoteAccessibilityInputConnectionInvoker(connection, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link IRemoteAccessibilityInputConnectionInvoker} with the given
|
||||
* {@code sessionId}.
|
||||
*
|
||||
* @param sessionId the new session ID to be used.
|
||||
* @return A new instance of {@link IRemoteAccessibilityInputConnectionInvoker}.
|
||||
*/
|
||||
@NonNull
|
||||
public IRemoteAccessibilityInputConnectionInvoker cloneWithSessionId(int sessionId) {
|
||||
return new IRemoteAccessibilityInputConnectionInvoker(mConnection, sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connection {@code IRemoteAccessibilityInputConnection} to be compared with
|
||||
* @return {@code true} if the underlying {@code IRemoteAccessibilityInputConnection} is the
|
||||
* same. {@code false} if {@code connection} is {@code null}.
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean isSameConnection(@NonNull IRemoteAccessibilityInputConnection connection) {
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
return mConnection.asBinder() == connection.asBinder();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
InputConnectionCommandHeader createHeader() {
|
||||
return new InputConnectionCommandHeader(mSessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#commitText(InputConnectionCommandHeader,
|
||||
* int, CharSequence)}.
|
||||
*
|
||||
* @param text {@code text} parameter to be passed.
|
||||
* @param newCursorPosition {@code newCursorPosition} parameter to be passed.
|
||||
* @param textAttribute The extra information about the text.
|
||||
*/
|
||||
@AnyThread
|
||||
public void commitText(CharSequence text, int newCursorPosition,
|
||||
@Nullable TextAttribute textAttribute) {
|
||||
try {
|
||||
mConnection.commitText(createHeader(), text, newCursorPosition, textAttribute);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#setSelection(InputConnectionCommandHeader,
|
||||
* int, int)}.
|
||||
*
|
||||
* @param start {@code start} parameter to be passed.
|
||||
* @param end {@code start} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void setSelection(int start, int end) {
|
||||
try {
|
||||
mConnection.setSelection(createHeader(), start, end);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#getSurroundingText(
|
||||
* InputConnectionCommandHeader, int, int, int, AndroidFuture)}.
|
||||
*
|
||||
* @param beforeLength {@code beforeLength} parameter to be passed.
|
||||
* @param afterLength {@code afterLength} parameter to be passed.
|
||||
* @param flags {@code flags} parameter to be passed.
|
||||
* @return {@link AndroidFuture< SurroundingText >} that can be used to retrieve the
|
||||
* invocation result. {@link RemoteException} will be treated as an error.
|
||||
*/
|
||||
@AnyThread
|
||||
@NonNull
|
||||
public AndroidFuture<SurroundingText> getSurroundingText(int beforeLength, int afterLength,
|
||||
int flags) {
|
||||
final AndroidFuture<SurroundingText> future = new AndroidFuture<>();
|
||||
try {
|
||||
mConnection.getSurroundingText(createHeader(), beforeLength, afterLength, flags,
|
||||
future);
|
||||
} catch (RemoteException e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#deleteSurroundingText(
|
||||
* InputConnectionCommandHeader, int, int)}.
|
||||
*
|
||||
* @param beforeLength {@code beforeLength} parameter to be passed.
|
||||
* @param afterLength {@code afterLength} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
try {
|
||||
mConnection.deleteSurroundingText(createHeader(), beforeLength, afterLength);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#sendKeyEvent(
|
||||
* InputConnectionCommandHeader, KeyEvent)}.
|
||||
*
|
||||
* @param event {@code event} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void sendKeyEvent(KeyEvent event) {
|
||||
try {
|
||||
mConnection.sendKeyEvent(createHeader(), event);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#performEditorAction(
|
||||
* InputConnectionCommandHeader, int)}.
|
||||
*
|
||||
* @param actionCode {@code start} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void performEditorAction(int actionCode) {
|
||||
try {
|
||||
mConnection.performEditorAction(createHeader(), actionCode);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#performContextMenuAction(
|
||||
* InputConnectionCommandHeader, int)}.
|
||||
*
|
||||
* @param id {@code id} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void performContextMenuAction(int id) {
|
||||
try {
|
||||
mConnection.performContextMenuAction(createHeader(), id);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#getCursorCapsMode(
|
||||
* InputConnectionCommandHeader, int, AndroidFuture)}.
|
||||
*
|
||||
* @param reqModes {@code reqModes} parameter to be passed.
|
||||
* @return {@link AndroidFuture<Integer>} that can be used to retrieve the invocation
|
||||
* result. {@link RemoteException} will be treated as an error.
|
||||
*/
|
||||
@AnyThread
|
||||
@NonNull
|
||||
public AndroidFuture<Integer> getCursorCapsMode(int reqModes) {
|
||||
final AndroidFuture<Integer> future = new AndroidFuture<>();
|
||||
try {
|
||||
mConnection.getCursorCapsMode(createHeader(), reqModes, future);
|
||||
} catch (RemoteException e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#clearMetaKeyStates(
|
||||
* InputConnectionCommandHeader, int)}.
|
||||
*
|
||||
* @param states {@code states} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void clearMetaKeyStates(int states) {
|
||||
try {
|
||||
mConnection.clearMetaKeyStates(createHeader(), states);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public final class InputBindResult implements Parcelable {
|
||||
/**
|
||||
* The accessibility services.
|
||||
*/
|
||||
public SparseArray<IInputMethodSession> accessibilitySessions;
|
||||
public SparseArray<IAccessibilityInputMethodSession> accessibilitySessions;
|
||||
|
||||
/**
|
||||
* The input channel used to send input events to this IME.
|
||||
@@ -231,8 +231,8 @@ public final class InputBindResult implements Parcelable {
|
||||
*
|
||||
* @param result A result code defined in {@link ResultCode}.
|
||||
* @param method {@link IInputMethodSession} to interact with the IME.
|
||||
* @param accessibilitySessions {@link IInputMethodSession} to interact with accessibility
|
||||
* services.
|
||||
* @param accessibilitySessions {@link IAccessibilityInputMethodSession} to interact with
|
||||
* accessibility services.
|
||||
* @param channel {@link InputChannel} to forward input events to the IME.
|
||||
* @param id The {@link String} representations of the IME, which is the same as
|
||||
* {@link android.view.inputmethod.InputMethodInfo#getId()} and
|
||||
@@ -242,7 +242,8 @@ public final class InputBindResult implements Parcelable {
|
||||
* {@code suppressesSpellChecker="true"}.
|
||||
*/
|
||||
public InputBindResult(@ResultCode int result,
|
||||
IInputMethodSession method, SparseArray<IInputMethodSession> accessibilitySessions,
|
||||
IInputMethodSession method,
|
||||
SparseArray<IAccessibilityInputMethodSession> accessibilitySessions,
|
||||
InputChannel channel, String id, int sequence,
|
||||
@Nullable Matrix virtualDisplayToScreenMatrix,
|
||||
boolean isInputMethodSuppressingSpellChecker) {
|
||||
@@ -271,8 +272,9 @@ public final class InputBindResult implements Parcelable {
|
||||
accessibilitySessions = new SparseArray<>(n);
|
||||
while (n > 0) {
|
||||
int key = source.readInt();
|
||||
IInputMethodSession value =
|
||||
IInputMethodSession.Stub.asInterface(source.readStrongBinder());
|
||||
IAccessibilityInputMethodSession value =
|
||||
IAccessibilityInputMethodSession.Stub.asInterface(
|
||||
source.readStrongBinder());
|
||||
accessibilitySessions.append(key, value);
|
||||
n--;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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 com.android.internal.inputmethod;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.DurationMillisLong;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.SurroundingText;
|
||||
import android.view.inputmethod.TextAttribute;
|
||||
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
import com.android.internal.view.IInputMethod;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* A wrapper object for A11y IME.
|
||||
*
|
||||
* <p>This needs to be public to be referenced from {@link android.app.UiAutomation}.</p>
|
||||
*/
|
||||
public final class RemoteAccessibilityInputConnection {
|
||||
private static final String TAG = "RemoteA11yInputConnection";
|
||||
|
||||
@DurationMillisLong
|
||||
private static final int MAX_WAIT_TIME_MILLIS = 2000;
|
||||
|
||||
@NonNull
|
||||
IRemoteAccessibilityInputConnectionInvoker mInvoker;
|
||||
|
||||
/**
|
||||
* Signaled when the system decided to take away IME focus from the target app.
|
||||
*
|
||||
* <p>This is expected to be signaled immediately when the IME process receives
|
||||
* {@link IInputMethod#unbindInput()}.</p>
|
||||
*/
|
||||
@NonNull
|
||||
private final CancellationGroup mCancellationGroup;
|
||||
|
||||
public RemoteAccessibilityInputConnection(
|
||||
@NonNull IRemoteAccessibilityInputConnection connection,
|
||||
@NonNull CancellationGroup cancellationGroup) {
|
||||
mInvoker = IRemoteAccessibilityInputConnectionInvoker.create(connection);
|
||||
mCancellationGroup = cancellationGroup;
|
||||
}
|
||||
|
||||
public RemoteAccessibilityInputConnection(@NonNull RemoteAccessibilityInputConnection original,
|
||||
int sessionId) {
|
||||
mInvoker = original.mInvoker.cloneWithSessionId(sessionId);
|
||||
mCancellationGroup = original.mCancellationGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this object holds the given {@link IRemoteAccessibilityInputConnection} or not.
|
||||
*
|
||||
* @param connection {@link IRemoteAccessibilityInputConnection} to be tested.
|
||||
* @return {@code true} if this object holds the same object.
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean isSameConnection(@NonNull IRemoteAccessibilityInputConnection connection) {
|
||||
return mInvoker.isSameConnection(connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#commitText(InputConnectionCommandHeader,
|
||||
* CharSequence, int, TextAttribute)}.
|
||||
*
|
||||
* @param text The {@code "text"} parameter to be passed.
|
||||
* @param newCursorPosition The {@code "newCursorPosition"} parameter to be passed.
|
||||
* @param textAttribute The {@code "textAttribute"} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void commitText(@NonNull CharSequence text, int newCursorPosition,
|
||||
@Nullable TextAttribute textAttribute) {
|
||||
mInvoker.commitText(text, newCursorPosition, textAttribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#setSelection(InputConnectionCommandHeader,
|
||||
* int, int)}.
|
||||
*
|
||||
* @param start The {@code "start"} parameter to be passed.
|
||||
* @param end The {@code "end"} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void setSelection(int start, int end) {
|
||||
mInvoker.setSelection(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#getSurroundingText(
|
||||
* InputConnectionCommandHeader, int, int, int, AndroidFuture)}.
|
||||
*
|
||||
* @param beforeLength The {@code "beforeLength"} parameter to be passed.
|
||||
* @param afterLength The {@code "afterLength"} parameter to be passed.
|
||||
* @param flags The {@code "flags"} parameter to be passed.
|
||||
* @return The {@link SurroundingText} object returned from the target application.
|
||||
*/
|
||||
@AnyThread
|
||||
public SurroundingText getSurroundingText(
|
||||
@IntRange(from = 0) int beforeLength, @IntRange(from = 0) int afterLength, int flags) {
|
||||
if (beforeLength < 0) {
|
||||
throw new IllegalArgumentException("beforeLength cannot be negative but was "
|
||||
+ beforeLength);
|
||||
}
|
||||
if (afterLength < 0) {
|
||||
throw new IllegalArgumentException("afterLength cannot be negative but was "
|
||||
+ afterLength);
|
||||
}
|
||||
if (mCancellationGroup.isCanceled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CompletableFuture<SurroundingText> value = mInvoker.getSurroundingText(beforeLength,
|
||||
afterLength, flags);
|
||||
return CompletableFutureUtil.getResultOrNull(
|
||||
value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#deleteSurroundingText(
|
||||
* InputConnectionCommandHeader, int, int)}.
|
||||
*
|
||||
* @param beforeLength The {@code "beforeLength"} parameter to be passed.
|
||||
* @param afterLength The {@code "afterLength"} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
mInvoker.deleteSurroundingText(beforeLength, afterLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#sendKeyEvent(InputConnectionCommandHeader,
|
||||
* KeyEvent)}.
|
||||
*
|
||||
* @param event The {@code "event"} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void sendKeyEvent(KeyEvent event) {
|
||||
mInvoker.sendKeyEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#performEditorAction(
|
||||
* InputConnectionCommandHeader, int)}.
|
||||
*
|
||||
* @param actionCode The {@code "actionCode"} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void performEditorAction(int actionCode) {
|
||||
mInvoker.performEditorAction(actionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#performContextMenuAction(
|
||||
* InputConnectionCommandHeader, int)}.
|
||||
*
|
||||
* @param id The {@code "id"} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void performContextMenuAction(int id) {
|
||||
mInvoker.performContextMenuAction(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#getCursorCapsMode(
|
||||
* InputConnectionCommandHeader, int, AndroidFuture)}.
|
||||
*
|
||||
* @param reqModes The {@code "reqModes"} parameter to be passed.
|
||||
* @return integer result returned from the target application.
|
||||
*/
|
||||
@AnyThread
|
||||
public int getCursorCapsMode(int reqModes) {
|
||||
if (mCancellationGroup.isCanceled()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final CompletableFuture<Integer> value = mInvoker.getCursorCapsMode(reqModes);
|
||||
|
||||
return CompletableFutureUtil.getResultOrZero(
|
||||
value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IRemoteAccessibilityInputConnection#clearMetaKeyStates(
|
||||
* InputConnectionCommandHeader, int)}.
|
||||
*
|
||||
* @param states The {@code "states"} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void clearMetaKeyStates(int states) {
|
||||
mInvoker.clearMetaKeyStates(states);
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,13 @@ import java.util.function.Supplier;
|
||||
* {@link IInputContext} binder calls in the IME client (editor app) process, and forwards them to
|
||||
* {@link InputConnection} that the IME client provided, on the {@link Looper} associated to the
|
||||
* {@link InputConnection}.</p>
|
||||
*
|
||||
* <p>{@link com.android.internal.inputmethod.RemoteAccessibilityInputConnection} code is executed
|
||||
* in the {@link android.accessibilityservice.AccessibilityService} process. It makes
|
||||
* {@link com.android.internal.inputmethod.IRemoteAccessibilityInputConnection} binder calls under
|
||||
* the hood. {@link #mAccessibilityInputConnection} receives the binder calls in the IME client
|
||||
* (editor app) process, and forwards them to {@link InputConnection} that the IME client provided,
|
||||
* on the {@link Looper} associated to the {@link InputConnection}.</p>
|
||||
*/
|
||||
public final class RemoteInputConnectionImpl extends IInputContext.Stub {
|
||||
private static final String TAG = "RemoteInputConnectionImpl";
|
||||
@@ -1043,6 +1050,175 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
|
||||
});
|
||||
}
|
||||
|
||||
private final IRemoteAccessibilityInputConnection mAccessibilityInputConnection =
|
||||
new IRemoteAccessibilityInputConnection.Stub() {
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void commitText(InputConnectionCommandHeader header, CharSequence text,
|
||||
int newCursorPosition, @Nullable TextAttribute textAttribute) {
|
||||
dispatchWithTracing("commitTextFromA11yIme", () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return; // cancelled
|
||||
}
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "commitText on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.commitText(text, newCursorPosition, textAttribute);
|
||||
});
|
||||
}
|
||||
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void setSelection(InputConnectionCommandHeader header, int start, int end) {
|
||||
dispatchWithTracing("setSelectionFromA11yIme", () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return; // cancelled
|
||||
}
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "setSelection on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.setSelection(start, end);
|
||||
});
|
||||
}
|
||||
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void getSurroundingText(InputConnectionCommandHeader header, int beforeLength,
|
||||
int afterLength, int flags, AndroidFuture future /* T=SurroundingText */) {
|
||||
dispatchWithTracing("getSurroundingTextFromA11yIme", future, () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return null; // cancelled
|
||||
}
|
||||
final InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "getSurroundingText on inactive InputConnection");
|
||||
return null;
|
||||
}
|
||||
if (beforeLength < 0) {
|
||||
Log.i(TAG, "Returning null to getSurroundingText due to an invalid"
|
||||
+ " beforeLength=" + beforeLength);
|
||||
return null;
|
||||
}
|
||||
if (afterLength < 0) {
|
||||
Log.i(TAG, "Returning null to getSurroundingText due to an invalid"
|
||||
+ " afterLength=" + afterLength);
|
||||
return null;
|
||||
}
|
||||
return ic.getSurroundingText(beforeLength, afterLength, flags);
|
||||
}, useImeTracing() ? result -> buildGetSurroundingTextProto(
|
||||
beforeLength, afterLength, flags, result) : null);
|
||||
}
|
||||
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void deleteSurroundingText(InputConnectionCommandHeader header, int beforeLength,
|
||||
int afterLength) {
|
||||
dispatchWithTracing("deleteSurroundingTextFromA11yIme", () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return; // cancelled
|
||||
}
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.deleteSurroundingText(beforeLength, afterLength);
|
||||
});
|
||||
}
|
||||
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void sendKeyEvent(InputConnectionCommandHeader header, KeyEvent event) {
|
||||
dispatchWithTracing("sendKeyEventFromA11yIme", () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return; // cancelled
|
||||
}
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "sendKeyEvent on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.sendKeyEvent(event);
|
||||
});
|
||||
}
|
||||
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void performEditorAction(InputConnectionCommandHeader header, int id) {
|
||||
dispatchWithTracing("performEditorActionFromA11yIme", () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return; // cancelled
|
||||
}
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "performEditorAction on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.performEditorAction(id);
|
||||
});
|
||||
}
|
||||
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void performContextMenuAction(InputConnectionCommandHeader header, int id) {
|
||||
dispatchWithTracing("performContextMenuActionFromA11yIme", () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return; // cancelled
|
||||
}
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "performContextMenuAction on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.performContextMenuAction(id);
|
||||
});
|
||||
}
|
||||
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void getCursorCapsMode(InputConnectionCommandHeader header, int reqModes,
|
||||
AndroidFuture future /* T=Integer */) {
|
||||
dispatchWithTracing("getCursorCapsModeFromA11yIme", future, () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return 0; // cancelled
|
||||
}
|
||||
final InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
|
||||
return 0;
|
||||
}
|
||||
return ic.getCursorCapsMode(reqModes);
|
||||
}, useImeTracing() ? result -> buildGetCursorCapsModeProto(reqModes, result) : null);
|
||||
}
|
||||
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void clearMetaKeyStates(InputConnectionCommandHeader header, int states) {
|
||||
dispatchWithTracing("clearMetaKeyStatesFromA11yIme", () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
return; // cancelled
|
||||
}
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.clearMetaKeyStates(states);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {@link IRemoteAccessibilityInputConnection} associated with this object.
|
||||
*/
|
||||
public IRemoteAccessibilityInputConnection asIRemoteAccessibilityInputConnection() {
|
||||
return mAccessibilityInputConnection;
|
||||
}
|
||||
|
||||
private void dispatch(@NonNull Runnable runnable) {
|
||||
// If we are calling this from the target thread, then we can call right through.
|
||||
// Otherwise, we need to send the message to the target thread.
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.view.inputmethod.InputMethodSubtype;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
|
||||
import com.android.internal.inputmethod.InputBindResult;
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
import com.android.internal.view.IInputContext;
|
||||
import com.android.internal.view.IInputMethodClient;
|
||||
|
||||
@@ -54,7 +55,8 @@ interface IInputMethodManager {
|
||||
in IInputMethodClient client, in IBinder windowToken,
|
||||
/* @StartInputFlags */ int startInputFlags,
|
||||
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
|
||||
int windowFlags, in EditorInfo attribute, IInputContext inputContext,
|
||||
int windowFlags, in EditorInfo attribute, in IInputContext inputContext,
|
||||
in IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
|
||||
int unverifiedTargetSdkVersion);
|
||||
|
||||
void showInputMethodPickerFromClient(in IInputMethodClient client,
|
||||
|
||||
@@ -84,16 +84,15 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityWindowInfo;
|
||||
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputBinding;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.compat.IPlatformCompat;
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
import com.android.internal.os.SomeArgs;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
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 com.android.server.LocalServices;
|
||||
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
|
||||
import com.android.server.accessibility.magnification.MagnificationProcessor;
|
||||
@@ -1655,21 +1654,22 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
mInvocationHandler.createImeSessionLocked();
|
||||
}
|
||||
|
||||
public void setImeSessionEnabledLocked(IInputMethodSession session, boolean enabled) {
|
||||
public void setImeSessionEnabledLocked(IAccessibilityInputMethodSession session,
|
||||
boolean enabled) {
|
||||
mInvocationHandler.setImeSessionEnabledLocked(session, enabled);
|
||||
}
|
||||
|
||||
public void bindInputLocked(InputBinding binding) {
|
||||
mInvocationHandler.bindInputLocked(binding);
|
||||
public void bindInputLocked() {
|
||||
mInvocationHandler.bindInputLocked();
|
||||
}
|
||||
|
||||
public void unbindInputLocked() {
|
||||
mInvocationHandler.unbindInputLocked();
|
||||
}
|
||||
|
||||
public void startInputLocked(IBinder startInputToken, IInputContext inputContext,
|
||||
public void startInputLocked(IRemoteAccessibilityInputConnection connection,
|
||||
EditorInfo editorInfo, boolean restarting) {
|
||||
mInvocationHandler.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
|
||||
mInvocationHandler.startInputLocked(connection, editorInfo, restarting);
|
||||
}
|
||||
|
||||
|
||||
@@ -1827,7 +1827,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
}
|
||||
}
|
||||
|
||||
private void setImeSessionEnabledInternal(IInputMethodSession session, boolean enabled) {
|
||||
private void setImeSessionEnabledInternal(IAccessibilityInputMethodSession session,
|
||||
boolean enabled) {
|
||||
final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
|
||||
if (listener != null && session != null) {
|
||||
try {
|
||||
@@ -1842,14 +1843,14 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
}
|
||||
}
|
||||
|
||||
private void bindInputInternal(InputBinding binding) {
|
||||
private void bindInputInternal() {
|
||||
final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
|
||||
if (listener != null) {
|
||||
try {
|
||||
if (svcClientTracingEnabled()) {
|
||||
logTraceSvcClient("bindInput", binding.toString());
|
||||
logTraceSvcClient("bindInput", "");
|
||||
}
|
||||
listener.bindInput(binding);
|
||||
listener.bindInput();
|
||||
} catch (RemoteException re) {
|
||||
Slog.e(LOG_TAG,
|
||||
"Error binding input to " + mService, re);
|
||||
@@ -1872,16 +1873,16 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
}
|
||||
}
|
||||
|
||||
private void startInputInternal(IBinder startInputToken, IInputContext inputContext,
|
||||
private void startInputInternal(IRemoteAccessibilityInputConnection connection,
|
||||
EditorInfo editorInfo, boolean restarting) {
|
||||
final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
|
||||
if (listener != null) {
|
||||
try {
|
||||
if (svcClientTracingEnabled()) {
|
||||
logTraceSvcClient("startInput", startInputToken + " "
|
||||
+ inputContext + " " + editorInfo + restarting);
|
||||
logTraceSvcClient("startInput", "editorInfo=" + editorInfo
|
||||
+ " restarting=" + restarting);
|
||||
}
|
||||
listener.startInput(startInputToken, inputContext, editorInfo, restarting);
|
||||
listener.startInput(connection, editorInfo, restarting);
|
||||
} catch (RemoteException re) {
|
||||
Slog.e(LOG_TAG,
|
||||
"Error starting input to " + mService, re);
|
||||
@@ -2141,12 +2142,12 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
break;
|
||||
case MSG_SET_IME_SESSION_ENABLED:
|
||||
final boolean enabled = (message.arg1 != 0);
|
||||
final IInputMethodSession session = (IInputMethodSession) message.obj;
|
||||
final IAccessibilityInputMethodSession session =
|
||||
(IAccessibilityInputMethodSession) message.obj;
|
||||
setImeSessionEnabledInternal(session, enabled);
|
||||
break;
|
||||
case MSG_BIND_INPUT:
|
||||
final InputBinding binding = (InputBinding) message.obj;
|
||||
bindInputInternal(binding);
|
||||
bindInputInternal();
|
||||
break;
|
||||
case MSG_UNBIND_INPUT:
|
||||
unbindInputInternal();
|
||||
@@ -2154,10 +2155,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
case MSG_START_INPUT:
|
||||
final boolean restarting = (message.arg1 != 0);
|
||||
final SomeArgs args = (SomeArgs) message.obj;
|
||||
final IBinder startInputToken = (IBinder) args.arg1;
|
||||
final IInputContext inputContext = (IInputContext) args.arg2;
|
||||
final EditorInfo editorInfo = (EditorInfo) args.arg3;
|
||||
startInputInternal(startInputToken, inputContext, editorInfo, restarting);
|
||||
final IRemoteAccessibilityInputConnection connection =
|
||||
(IRemoteAccessibilityInputConnection) args.arg1;
|
||||
final EditorInfo editorInfo = (EditorInfo) args.arg2;
|
||||
startInputInternal(connection, editorInfo, restarting);
|
||||
args.recycle();
|
||||
break;
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown message: " + type);
|
||||
@@ -2227,14 +2229,15 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
public void setImeSessionEnabledLocked(IInputMethodSession session, boolean enabled) {
|
||||
public void setImeSessionEnabledLocked(IAccessibilityInputMethodSession session,
|
||||
boolean enabled) {
|
||||
final Message msg = obtainMessage(MSG_SET_IME_SESSION_ENABLED, (enabled ? 1 : 0),
|
||||
0, session);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
public void bindInputLocked(InputBinding binding) {
|
||||
final Message msg = obtainMessage(MSG_BIND_INPUT, binding);
|
||||
public void bindInputLocked() {
|
||||
final Message msg = obtainMessage(MSG_BIND_INPUT);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
@@ -2243,12 +2246,12 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
public void startInputLocked(IBinder startInputToken, IInputContext inputContext,
|
||||
public void startInputLocked(
|
||||
IRemoteAccessibilityInputConnection connection,
|
||||
EditorInfo editorInfo, boolean restarting) {
|
||||
final SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = startInputToken;
|
||||
args.arg2 = inputContext;
|
||||
args.arg3 = editorInfo;
|
||||
args.arg1 = connection;
|
||||
args.arg2 = editorInfo;
|
||||
final Message msg = obtainMessage(MSG_START_INPUT, restarting ? 1 : 0, 0, args);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
@@ -2402,10 +2405,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AccessibilityCallback extends IInputSessionWithIdCallback.Stub {
|
||||
private static final class AccessibilityCallback
|
||||
extends IAccessibilityInputMethodSessionCallback.Stub {
|
||||
@Override
|
||||
public void sessionCreated(IInputMethodSession session, int id) {
|
||||
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.sessionCreated");
|
||||
public void sessionCreated(IAccessibilityInputMethodSession session, int id) {
|
||||
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AACS.sessionCreated");
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
InputMethodManagerInternal.get().onSessionForAccessibilityCreated(id, session);
|
||||
|
||||
@@ -118,7 +118,6 @@ import android.view.accessibility.IAccessibilityManager;
|
||||
import android.view.accessibility.IAccessibilityManagerClient;
|
||||
import android.view.accessibility.IWindowMagnificationConnection;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputBinding;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.accessibility.AccessibilityShortcutController;
|
||||
@@ -128,12 +127,12 @@ import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserAct
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.IntPair;
|
||||
import com.android.internal.view.IInputContext;
|
||||
import com.android.internal.view.IInputMethodSession;
|
||||
import com.android.server.AccessibilityManagerInternal;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
@@ -281,9 +280,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
private Point mTempPoint = new Point();
|
||||
private boolean mIsAccessibilityButtonShown;
|
||||
|
||||
private InputBinding mInputBinding;
|
||||
IBinder mStartInputToken;
|
||||
IInputContext mInputContext;
|
||||
private boolean mInputBound;
|
||||
IRemoteAccessibilityInputConnection mRemoteInputConnection;
|
||||
EditorInfo mEditorInfo;
|
||||
boolean mRestarting;
|
||||
boolean mInputSessionRequested;
|
||||
@@ -322,7 +320,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
|
||||
public void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions,
|
||||
boolean enabled) {
|
||||
mService.scheduleSetImeSessionEnabled(sessions, enabled);
|
||||
}
|
||||
@@ -333,8 +331,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindInput(InputBinding binding) {
|
||||
mService.scheduleBindInput(binding);
|
||||
public void bindInput() {
|
||||
mService.scheduleBindInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -343,9 +341,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startInput(IBinder startInputToken, IInputContext inputContext,
|
||||
public void startInput(
|
||||
IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
|
||||
EditorInfo editorInfo, boolean restarting) {
|
||||
mService.scheduleStartInput(startInputToken, inputContext, editorInfo, restarting);
|
||||
mService.scheduleStartInput(remoteAccessibilityInputConnection, editorInfo, restarting);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4350,10 +4349,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
|
||||
private void bindAndStartInputForConnection(AbstractAccessibilityServiceConnection connection) {
|
||||
synchronized (mLock) {
|
||||
if (mInputBinding != null) {
|
||||
connection.bindInputLocked(mInputBinding);
|
||||
connection.startInputLocked(mStartInputToken, mInputContext, mEditorInfo,
|
||||
mRestarting);
|
||||
if (mInputBound) {
|
||||
connection.bindInputLocked();
|
||||
connection.startInputLocked(mRemoteInputConnection, mEditorInfo, mRestarting);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4396,23 +4394,20 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
|
||||
/**
|
||||
* Bind input for accessibility services which request ime capabilities.
|
||||
*
|
||||
* @param binding Information given to an accessibility service about a client connecting to it.
|
||||
*/
|
||||
public void scheduleBindInput(InputBinding binding) {
|
||||
mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this,
|
||||
binding));
|
||||
public void scheduleBindInput() {
|
||||
mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this));
|
||||
}
|
||||
|
||||
private void bindInput(InputBinding binding) {
|
||||
private void bindInput() {
|
||||
synchronized (mLock) {
|
||||
// Keep records of these in case new Accessibility Services are enabled.
|
||||
mInputBinding = binding;
|
||||
mInputBound = true;
|
||||
AccessibilityUserState userState = getCurrentUserStateLocked();
|
||||
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
|
||||
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
|
||||
if (service.requestImeApis()) {
|
||||
service.bindInputLocked(binding);
|
||||
service.bindInputLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4427,6 +4422,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
|
||||
private void unbindInput() {
|
||||
synchronized (mLock) {
|
||||
mInputBound = false;
|
||||
AccessibilityUserState userState = getCurrentUserStateLocked();
|
||||
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
|
||||
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
|
||||
@@ -4440,25 +4436,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
/**
|
||||
* Start input for accessibility services which request ime capabilities.
|
||||
*/
|
||||
public void scheduleStartInput(IBinder startInputToken, IInputContext inputContext,
|
||||
public void scheduleStartInput(IRemoteAccessibilityInputConnection connection,
|
||||
EditorInfo editorInfo, boolean restarting) {
|
||||
mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::startInput, this,
|
||||
startInputToken, inputContext, editorInfo, restarting));
|
||||
connection, editorInfo, restarting));
|
||||
}
|
||||
|
||||
private void startInput(IBinder startInputToken, IInputContext inputContext,
|
||||
EditorInfo editorInfo, boolean restarting) {
|
||||
private void startInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo,
|
||||
boolean restarting) {
|
||||
synchronized (mLock) {
|
||||
// Keep records of these in case new Accessibility Services are enabled.
|
||||
mStartInputToken = startInputToken;
|
||||
mInputContext = inputContext;
|
||||
mRemoteInputConnection = connection;
|
||||
mEditorInfo = editorInfo;
|
||||
mRestarting = restarting;
|
||||
AccessibilityUserState userState = getCurrentUserStateLocked();
|
||||
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
|
||||
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
|
||||
if (service.requestImeApis()) {
|
||||
service.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
|
||||
service.startInputLocked(connection, editorInfo, restarting);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4492,13 +4487,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|
||||
* @param sessions Sessions to enable or disable.
|
||||
* @param enabled True if enable the sessions or false if disable the sessions.
|
||||
*/
|
||||
public void scheduleSetImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
|
||||
public void scheduleSetImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions,
|
||||
boolean enabled) {
|
||||
mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::setImeSessionEnabled,
|
||||
this, sessions, enabled));
|
||||
}
|
||||
|
||||
private void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
|
||||
private void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions,
|
||||
boolean enabled) {
|
||||
synchronized (mLock) {
|
||||
AccessibilityUserState userState = getCurrentUserStateLocked();
|
||||
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
|
||||
|
||||
@@ -17,28 +17,26 @@
|
||||
package com.android.server;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.IBinder;
|
||||
import android.util.ArraySet;
|
||||
import android.util.SparseArray;
|
||||
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.inputmethod.IAccessibilityInputMethodSession;
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
|
||||
/**
|
||||
* Accessibility manager local system service interface.
|
||||
*/
|
||||
public abstract class AccessibilityManagerInternal {
|
||||
/** Enable or disable the sessions. */
|
||||
public abstract void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
|
||||
boolean enabled);
|
||||
public abstract void setImeSessionEnabled(
|
||||
SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled);
|
||||
|
||||
/** Unbind input for all accessibility services which require ime capabilities. */
|
||||
public abstract void unbindInput();
|
||||
|
||||
/** Bind input for all accessibility services which require ime capabilities. */
|
||||
public abstract void bindInput(InputBinding binding);
|
||||
public abstract void bindInput();
|
||||
|
||||
/**
|
||||
* Request input session from all accessibility services which require ime capabilities and
|
||||
@@ -47,12 +45,13 @@ public abstract class AccessibilityManagerInternal {
|
||||
public abstract void createImeSession(ArraySet<Integer> ignoreSet);
|
||||
|
||||
/** Start input for all accessibility services which require ime capabilities. */
|
||||
public abstract void startInput(IBinder startInputToken, IInputContext inputContext,
|
||||
public abstract void startInput(
|
||||
IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
|
||||
EditorInfo editorInfo, boolean restarting);
|
||||
|
||||
private static final AccessibilityManagerInternal NOP = new AccessibilityManagerInternal() {
|
||||
@Override
|
||||
public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
|
||||
public void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions,
|
||||
boolean enabled) {
|
||||
}
|
||||
|
||||
@@ -61,7 +60,7 @@ public abstract class AccessibilityManagerInternal {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindInput(InputBinding binding) {
|
||||
public void bindInput() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +68,7 @@ public abstract class AccessibilityManagerInternal {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startInput(IBinder startInputToken, IInputContext inputContext,
|
||||
public void startInput(IRemoteAccessibilityInputConnection remoteAccessibility,
|
||||
EditorInfo editorInfo, boolean restarting) {
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,9 +24,9 @@ import android.os.IBinder;
|
||||
import android.view.inputmethod.InlineSuggestionsRequest;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
|
||||
import com.android.internal.inputmethod.SoftInputShowHideReason;
|
||||
import com.android.internal.view.IInlineSuggestionsRequestCallback;
|
||||
import com.android.internal.view.IInputMethodSession;
|
||||
import com.android.internal.view.InlineSuggestionsRequestInfo;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
@@ -164,7 +164,7 @@ public abstract class InputMethodManagerInternal {
|
||||
* @param session The session passed back from the accessibility service.
|
||||
*/
|
||||
public abstract void onSessionForAccessibilityCreated(int accessibilityConnectionId,
|
||||
IInputMethodSession session);
|
||||
IAccessibilityInputMethodSession session);
|
||||
|
||||
/**
|
||||
* Unbind the accessibility service with the specified accessibilityConnectionId from current
|
||||
@@ -240,7 +240,7 @@ public abstract class InputMethodManagerInternal {
|
||||
|
||||
@Override
|
||||
public void onSessionForAccessibilityCreated(int accessibilityConnectionId,
|
||||
IInputMethodSession session) {
|
||||
IAccessibilityInputMethodSession session) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -155,8 +155,10 @@ import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
import com.android.internal.inputmethod.DirectBootAwareness;
|
||||
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
|
||||
import com.android.internal.inputmethod.IInputContentUriToken;
|
||||
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
|
||||
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
|
||||
import com.android.internal.inputmethod.ImeTracing;
|
||||
import com.android.internal.inputmethod.InputBindResult;
|
||||
import com.android.internal.inputmethod.InputMethodDebug;
|
||||
@@ -422,7 +424,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
// Id of the accessibility service.
|
||||
final int mId;
|
||||
|
||||
public IInputMethodSession mSession;
|
||||
public IAccessibilityInputMethodSession mSession;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -434,7 +436,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
|
||||
AccessibilitySessionState(ClientState client, int id,
|
||||
IInputMethodSession session) {
|
||||
IAccessibilityInputMethodSession session) {
|
||||
mClient = client;
|
||||
mId = id;
|
||||
mSession = session;
|
||||
@@ -613,6 +615,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
*/
|
||||
IInputContext mCurInputContext;
|
||||
|
||||
/**
|
||||
* The {@link IRemoteAccessibilityInputConnection} last provided by the current client.
|
||||
*/
|
||||
@Nullable IRemoteAccessibilityInputConnection mCurRemoteAccessibilityInputConnection;
|
||||
|
||||
/**
|
||||
* The attributes last provided by the current client.
|
||||
*/
|
||||
@@ -2627,7 +2634,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
final InputMethodInfo curInputMethodInfo = mMethodMap.get(curId);
|
||||
final boolean suppressesSpellChecker =
|
||||
curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
|
||||
final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
|
||||
final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions =
|
||||
createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
|
||||
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
|
||||
session.session, accessibilityInputMethodSessions,
|
||||
@@ -2666,7 +2673,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
InputBindResult attachNewAccessibilityLocked(@StartInputReason int startInputReason,
|
||||
boolean initial, int id) {
|
||||
if (!mBoundToAccessibility) {
|
||||
AccessibilityManagerInternal.get().bindInput(mCurClient.binding);
|
||||
AccessibilityManagerInternal.get().bindInput();
|
||||
mBoundToAccessibility = true;
|
||||
}
|
||||
|
||||
@@ -2680,14 +2687,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
if (startInputReason != StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY) {
|
||||
final Binder startInputToken = new Binder();
|
||||
setEnabledSessionForAccessibilityLocked(mCurClient.mAccessibilitySessions);
|
||||
AccessibilityManagerInternal.get().startInput(startInputToken, mCurInputContext,
|
||||
AccessibilityManagerInternal.get().startInput(mCurRemoteAccessibilityInputConnection,
|
||||
mCurAttribute, !initial /* restarting */);
|
||||
}
|
||||
|
||||
if (accessibilitySession != null) {
|
||||
final SessionState session = mCurClient.curSession;
|
||||
IInputMethodSession imeSession = session == null ? null : session.session;
|
||||
final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
|
||||
final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions =
|
||||
createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
|
||||
return new InputBindResult(
|
||||
InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
|
||||
@@ -2698,9 +2705,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
return null;
|
||||
}
|
||||
|
||||
private SparseArray<IInputMethodSession> createAccessibilityInputMethodSessions(
|
||||
private SparseArray<IAccessibilityInputMethodSession> createAccessibilityInputMethodSessions(
|
||||
SparseArray<AccessibilitySessionState> accessibilitySessions) {
|
||||
final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
|
||||
final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions =
|
||||
new SparseArray<>();
|
||||
if (accessibilitySessions != null) {
|
||||
for (int i = 0; i < accessibilitySessions.size(); i++) {
|
||||
@@ -2722,8 +2729,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
@GuardedBy("ImfLock.class")
|
||||
@NonNull
|
||||
private InputBindResult startInputUncheckedLocked(@NonNull ClientState cs,
|
||||
IInputContext inputContext, @NonNull EditorInfo attribute,
|
||||
@StartInputFlags int startInputFlags, @StartInputReason int startInputReason,
|
||||
IInputContext inputContext,
|
||||
@Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
|
||||
@NonNull EditorInfo attribute, @StartInputFlags int startInputFlags,
|
||||
@StartInputReason int startInputReason,
|
||||
int unverifiedTargetSdkVersion) {
|
||||
// If no method is currently selected, do nothing.
|
||||
final String selectedMethodId = getSelectedMethodIdLocked();
|
||||
@@ -2767,6 +2776,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
advanceSequenceNumberLocked();
|
||||
mCurClient = cs;
|
||||
mCurInputContext = inputContext;
|
||||
mCurRemoteAccessibilityInputConnection = remoteAccessibilityInputConnection;
|
||||
mCurVirtualDisplayToScreenMatrix =
|
||||
getVirtualDisplayToScreenMatrixLocked(cs.selfReportedDisplayId,
|
||||
mDisplayIdToShowIme);
|
||||
@@ -3769,10 +3779,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
@StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
|
||||
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
|
||||
int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
|
||||
IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
|
||||
int unverifiedTargetSdkVersion) {
|
||||
return startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
|
||||
startInputFlags, softInputMode, windowFlags, attribute, inputContext,
|
||||
unverifiedTargetSdkVersion);
|
||||
remoteAccessibilityInputConnection, unverifiedTargetSdkVersion);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -3780,6 +3791,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
@StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
|
||||
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
|
||||
int windowFlags, @Nullable EditorInfo attribute, @Nullable IInputContext inputContext,
|
||||
@Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
|
||||
int unverifiedTargetSdkVersion) {
|
||||
if (windowToken == null) {
|
||||
Slog.e(TAG, "windowToken cannot be null.");
|
||||
@@ -3816,7 +3828,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
try {
|
||||
result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
|
||||
client, windowToken, startInputFlags, softInputMode, windowFlags,
|
||||
attribute, inputContext, unverifiedTargetSdkVersion, userId);
|
||||
attribute, inputContext, remoteAccessibilityInputConnection,
|
||||
unverifiedTargetSdkVersion, userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -3842,7 +3855,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
@StartInputReason int startInputReason, IInputMethodClient client,
|
||||
@NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
|
||||
@SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
|
||||
IInputContext inputContext, int unverifiedTargetSdkVersion, @UserIdInt int userId) {
|
||||
IInputContext inputContext,
|
||||
@Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
|
||||
int unverifiedTargetSdkVersion, @UserIdInt int userId) {
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
|
||||
+ InputMethodDebug.startInputReasonToString(startInputReason)
|
||||
@@ -3935,7 +3950,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
+ InputMethodDebug.startInputReasonToString(startInputReason));
|
||||
}
|
||||
if (attribute != null) {
|
||||
return startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
|
||||
return startInputUncheckedLocked(cs, inputContext,
|
||||
remoteAccessibilityInputConnection, attribute, startInputFlags,
|
||||
startInputReason, unverifiedTargetSdkVersion);
|
||||
}
|
||||
return new InputBindResult(
|
||||
@@ -3976,8 +3992,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
// UI for input.
|
||||
if (isTextEditor && attribute != null
|
||||
&& shouldRestoreImeVisibility(windowToken, softInputMode)) {
|
||||
res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
|
||||
startInputReason, unverifiedTargetSdkVersion);
|
||||
res = startInputUncheckedLocked(cs, inputContext, remoteAccessibilityInputConnection,
|
||||
attribute, startInputFlags, startInputReason, unverifiedTargetSdkVersion);
|
||||
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
|
||||
SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
|
||||
return res;
|
||||
@@ -4015,8 +4031,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
// is more room for the target window + IME.
|
||||
if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
|
||||
if (attribute != null) {
|
||||
res = startInputUncheckedLocked(cs, inputContext, attribute,
|
||||
startInputFlags, startInputReason, unverifiedTargetSdkVersion);
|
||||
res = startInputUncheckedLocked(cs, inputContext,
|
||||
remoteAccessibilityInputConnection, attribute, startInputFlags,
|
||||
startInputReason, unverifiedTargetSdkVersion);
|
||||
didStart = true;
|
||||
}
|
||||
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
|
||||
@@ -4046,8 +4063,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
if (isSoftInputModeStateVisibleAllowed(
|
||||
unverifiedTargetSdkVersion, startInputFlags)) {
|
||||
if (attribute != null) {
|
||||
res = startInputUncheckedLocked(cs, inputContext, attribute,
|
||||
startInputFlags, startInputReason, unverifiedTargetSdkVersion);
|
||||
res = startInputUncheckedLocked(cs, inputContext,
|
||||
remoteAccessibilityInputConnection, attribute, startInputFlags,
|
||||
startInputReason, unverifiedTargetSdkVersion);
|
||||
didStart = true;
|
||||
}
|
||||
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
|
||||
@@ -4065,8 +4083,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
unverifiedTargetSdkVersion, startInputFlags)) {
|
||||
if (!sameWindowFocused) {
|
||||
if (attribute != null) {
|
||||
res = startInputUncheckedLocked(cs, inputContext, attribute,
|
||||
startInputFlags, startInputReason, unverifiedTargetSdkVersion);
|
||||
res = startInputUncheckedLocked(cs, inputContext,
|
||||
remoteAccessibilityInputConnection, attribute, startInputFlags,
|
||||
startInputReason, unverifiedTargetSdkVersion);
|
||||
didStart = true;
|
||||
}
|
||||
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
|
||||
@@ -4094,7 +4113,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
|
||||
}
|
||||
}
|
||||
res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
|
||||
res = startInputUncheckedLocked(cs, inputContext,
|
||||
remoteAccessibilityInputConnection, attribute, startInputFlags,
|
||||
startInputReason, unverifiedTargetSdkVersion);
|
||||
} else {
|
||||
res = InputBindResult.NULL_EDITOR_INFO;
|
||||
@@ -4850,7 +4870,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
void setEnabledSessionForAccessibilityLocked(
|
||||
SparseArray<AccessibilitySessionState> accessibilitySessions) {
|
||||
// mEnabledAccessibilitySessions could the same object as accessibilitySessions.
|
||||
SparseArray<IInputMethodSession> disabledSessions = new SparseArray<>();
|
||||
SparseArray<IAccessibilityInputMethodSession> disabledSessions = new SparseArray<>();
|
||||
for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
|
||||
if (!accessibilitySessions.contains(mEnabledAccessibilitySessions.keyAt(i))) {
|
||||
AccessibilitySessionState sessionState = mEnabledAccessibilitySessions.valueAt(i);
|
||||
@@ -4864,7 +4884,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
AccessibilityManagerInternal.get().setImeSessionEnabled(disabledSessions,
|
||||
false);
|
||||
}
|
||||
SparseArray<IInputMethodSession> enabledSessions = new SparseArray<>();
|
||||
SparseArray<IAccessibilityInputMethodSession> enabledSessions = new SparseArray<>();
|
||||
for (int i = 0; i < accessibilitySessions.size(); i++) {
|
||||
if (!mEnabledAccessibilitySessions.contains(accessibilitySessions.keyAt(i))) {
|
||||
AccessibilitySessionState sessionState = accessibilitySessions.valueAt(i);
|
||||
@@ -5709,7 +5729,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
|
||||
@Override
|
||||
public void onSessionForAccessibilityCreated(int accessibilityConnectionId,
|
||||
IInputMethodSession session) {
|
||||
IAccessibilityInputMethodSession session) {
|
||||
synchronized (ImfLock.class) {
|
||||
if (mCurClient != null) {
|
||||
clearClientSessionForAccessibilityLocked(mCurClient, accessibilityConnectionId);
|
||||
|
||||
Reference in New Issue
Block a user