Add FLAG_INPUT_METHOD_EDITOR to a11y

An accessibility service needs to set FLAG_INPUT_METHOD_EDITOR
accessibilityFlags to use ime apis. Capability is not added
per Phil's suggestion.

Bug: 187453053

Test: CTS test added.
Change-Id: I78703c48e343ba09c2a0bf61c3447eea7337cb49
This commit is contained in:
yingleiw
2022-01-24 18:37:54 -08:00
parent fb17e5ae7a
commit 8cb76d59ae
8 changed files with 59 additions and 33 deletions

View File

@@ -3259,6 +3259,7 @@ package android.accessibilityservice {
field public static final int FEEDBACK_VISUAL = 8; // 0x8
field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
field public static final int FLAG_INPUT_METHOD_EDITOR = 32768; // 0x8000
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
field public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 8192; // 0x2000
field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100

View File

@@ -825,10 +825,16 @@ public abstract class AccessibilityService extends Service {
for (int i = 0; i < mMagnificationControllers.size(); i++) {
mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
}
// TODO(b/187453053): If service requested ime capabilities
if (!mInputMethodInitialized) {
mInputMethod = onCreateInputMethod();
mInputMethodInitialized = true;
AccessibilityServiceInfo info = getServiceInfo();
if (info != null) {
boolean requestIme = (info.flags
& AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
if (requestIme && !mInputMethodInitialized) {
mInputMethod = onCreateInputMethod();
mInputMethodInitialized = true;
}
} else {
Log.e(LOG_TAG, "AccessibilityServiceInfo is null in dispatchServiceConnected");
}
}
if (mSoftKeyboardController != null) {
@@ -1885,7 +1891,7 @@ public abstract class AccessibilityService extends Service {
/**
* The default implementation returns our default {@link InputMethod}. Subclasses can override
* it to provide their own customized version. Accessibility services need to set the
* {@link AccessibilityServiceInfo#FLAG_REQUEST_IME_APIS} flag to use input method APIs.
* {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag to use input method APIs.
*
* @return the InputMethod.
*/
@@ -1898,7 +1904,7 @@ public abstract class AccessibilityService extends Service {
* Returns the InputMethod instance after the system calls {@link #onCreateInputMethod()},
* which may be used to input text or get editable text selection change notifications. It will
* return null if the accessibility service doesn't set the
* {@link AccessibilityServiceInfo#FLAG_REQUEST_IME_APIS} flag or the system doesn't call
* {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag or the system doesn't call
* {@link #onCreateInputMethod()}.
*
* @return the InputMethod instance

View File

@@ -390,6 +390,15 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
public static final int FLAG_SEND_MOTION_EVENTS = 0x0004000;
/**
* This flag makes the AccessibilityService an input method editor with a subset of input
* method editor capabilities: get the {@link android.view.inputmethod.InputConnection} and get
* text selection change notifications.
*
* @see AccessibilityService#getInputMethod()
*/
public static final int FLAG_INPUT_METHOD_EDITOR = 0x0008000;
/** {@hide} */
public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
@@ -497,6 +506,7 @@ public class AccessibilityServiceInfo implements Parcelable {
* @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
* @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
* @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK
* @see #FLAG_INPUT_METHOD_EDITOR
*/
public int flags;
@@ -1332,6 +1342,8 @@ public class AccessibilityServiceInfo implements Parcelable {
return "FLAG_REQUEST_FINGERPRINT_GESTURES";
case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK:
return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK";
case FLAG_INPUT_METHOD_EDITOR:
return "FLAG_INPUT_METHOD_EDITOR";
default:
return null;
}

View File

@@ -55,7 +55,7 @@ import java.util.concurrent.Executor;
* developers should override them as needed. Developers should also override
* {@link AccessibilityService#onCreateInputMethod()} to return
* their custom InputMethod implementation. Accessibility services also need to set the
* {@link AccessibilityServiceInfo#FLAG_REQUEST_IME_APIS} flag to use input method APIs.
* {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag to use input method APIs.
*/
public class InputMethod {
private static final String LOG_TAG = "A11yInputMethod";

View File

@@ -3910,6 +3910,8 @@
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_MULTI_FINGER_GESTURES}. -->
<flag name="flagRequestMultiFingerGestures" value="0x00001000" />
<flag name="flagSendMotionEvents" value="0x0004000" />
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR}. -->
<flag name="flagInputMethodEditor" value="0x0008000" />
</attr>
<!-- Component name of an activity that allows the user to modify
the settings for this service. This setting cannot be changed at runtime. -->

View File

@@ -188,6 +188,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
boolean mLastAccessibilityButtonCallbackState;
boolean mRequestImeApis;
int mFetchFlags;
long mNotificationTimeout;
@@ -385,6 +387,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
& AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
mRequestAccessibilityButton = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
// TODO(b/218193835): request ime when ime flag is set and clean up when ime flag is unset
mRequestImeApis = (info.flags
& AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
}
protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {

View File

@@ -4372,10 +4372,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
// TODO(b/187453053): mRequestedIme implementation
//if (service.mRequestedIme) {
service.bindInputLocked(binding);
//}
if (service.requestImeApis()) {
service.bindInputLocked(binding);
}
}
}
}
@@ -4390,10 +4389,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
// TODO(187453053): mRequestedIme implementation
//if (service.mRequestedIme) {
service.unbindInputLocked();
//}
if (service.requestImeApis()) {
service.unbindInputLocked();
}
}
}
}
@@ -4403,7 +4401,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
public void startInput(IBinder startInputToken, IInputContext inputContext,
EditorInfo editorInfo, boolean restarting) {
//TODO(b/187453053): including the java doc
AccessibilityUserState userState;
synchronized (mLock) {
// Keep records of these in case new Accessibility Services are enabled.
@@ -4414,10 +4411,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
// TODO(b/187453053): mRequestedIme implementation
//if (service.mRequestedIme) {
service.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
//}
if (service.requestImeApis()) {
service.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
}
}
}
}
@@ -4432,10 +4428,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
// TODO(b/187453053): mRequestedIme implementation
//if (service.mRequestedIme) {
service.createImeSessionLocked();
//}
if (service.requestImeApis()) {
service.createImeSessionLocked();
}
}
}
}
@@ -4452,11 +4447,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
// TODO(b/187453053): mRequestedIme implementation
if (sessions.contains(service.mId)) {
//if (service.mRequestedIme) {
if (sessions.contains(service.mId) && service.requestImeApis()) {
service.setImeSessionEnabledLocked(sessions.get(service.mId), enabled);
//}
}
}
}

View File

@@ -127,8 +127,9 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
public void unbindLocked() {
// If requested ime
mSystemSupport.unbindImeLocked(this);
if (requestImeApis()) {
mSystemSupport.unbindImeLocked(this);
}
mContext.unbindService(this);
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState == null) return;
@@ -190,8 +191,9 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
// the new configuration (for example, initializing the input filter).
mMainHandler.sendMessage(obtainMessage(
AccessibilityServiceConnection::initializeService, this));
//if (service.mRequestedIme) {
mSystemSupport.requestImeLocked(this);
if (requestImeApis()) {
mSystemSupport.requestImeLocked(this);
}
}
}
@@ -375,7 +377,9 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
if (!isConnectedLocked()) {
return;
}
mSystemSupport.unbindImeLocked(this);
if (requestImeApis()) {
mSystemSupport.unbindImeLocked(this);
}
mAccessibilityServiceInfo.crashed = true;
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState != null) {
@@ -517,6 +521,10 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
mMainHandler.sendMessage(msg);
}
public boolean requestImeApis() {
return mRequestImeApis;
}
private void notifyMotionEventInternal(MotionEvent event) {
final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
if (listener != null) {