Merge "Conditional Init HWController when device has supported stylus"

This commit is contained in:
Taran Singh
2022-07-09 07:47:56 +00:00
committed by Android (Google) Code Review
5 changed files with 221 additions and 35 deletions

View File

@@ -3109,6 +3109,7 @@ package android.view.inputmethod {
}
public final class InputMethodManager {
method public void addVirtualStylusIdForTestSession();
method public int getDisplayId();
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
method public boolean hasActiveInputConnection(@Nullable android.view.View);

View File

@@ -257,4 +257,13 @@ final class IInputMethodManagerInvoker {
throw e.rethrowFromSystemServer();
}
}
@AnyThread
void addVirtualStylusIdForTestSession(IInputMethodClient client) {
try {
mTarget.addVirtualStylusIdForTestSession(client);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}

View File

@@ -2442,6 +2442,17 @@ public final class InputMethodManager {
}
}
/**
*
* @hide
*/
@TestApi
public void addVirtualStylusIdForTestSession() {
synchronized (mH) {
mServiceInvoker.addVirtualStylusIdForTestSession(mClient);
}
}
/**
* An empty method only to avoid crashes of apps that call this method via reflection and do not
* handle {@link NoSuchMethodException} in a graceful manner.

View File

@@ -114,4 +114,9 @@ interface IInputMethodManager {
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
boolean isStylusHandwritingAvailableAsUser(int userId);
/** add virtual stylus id for test Stylus handwriting session **/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INJECT_EVENTS)")
void addVirtualStylusIdForTestSession(in IInputMethodClient client);
}

View File

@@ -90,6 +90,7 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Matrix;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManagerInternal;
@@ -118,6 +119,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@@ -128,6 +130,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
@@ -218,6 +221,8 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public final class InputMethodManagerService extends IInputMethodManager.Stub
implements Handler.Callback {
// Virtual device id for test.
private static final Integer VIRTUAL_STYLUS_ID_FOR_TEST = 999999;
static final boolean DEBUG = false;
static final String TAG = "InputMethodManagerService";
public static final String PROTO_ARG = "--proto";
@@ -348,6 +353,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
private boolean mNotificationShown;
@GuardedBy("ImfLock.class")
private final HandwritingModeController mHwController;
@GuardedBy("ImfLock.class")
private IntArray mStylusIds;
@GuardedBy("ImfLock.class")
@Nullable
@@ -1766,6 +1773,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
com.android.internal.R.array.config_nonPreemptibleInputMethods));
mHwController = new HandwritingModeController(thread.getLooper(),
new InkWindowInitializer());
registerDeviceListenerAndCheckStylusSupport();
}
private final class InkWindowInitializer implements Runnable {
@@ -3369,41 +3377,51 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void startStylusHandwriting(IInputMethodClient client) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.startStylusHandwriting");
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#startStylusHandwriting");
int uid = Binder.getCallingUid();
synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return;
}
final long ident = Binder.clearCallingIdentity();
try {
if (!canInteractWithImeLocked(uid, client, "startStylusHandwriting")) {
return;
}
if (!mBindingController.supportsStylusHandwriting()) {
Slog.w(TAG, "Stylus HW unsupported by IME. Ignoring startStylusHandwriting()");
return;
}
final OptionalInt requestId = mHwController.getCurrentRequestId();
if (!requestId.isPresent()) {
Slog.e(TAG, "Stylus handwriting was not initialized.");
return;
}
if (!mHwController.isStylusGestureOngoing()) {
Slog.e(TAG, "There is no ongoing stylus gesture to start stylus handwriting.");
return;
}
if (DEBUG) Slog.v(TAG, "Client requesting Stylus Handwriting to be started");
final IInputMethodInvoker curMethod = getCurMethodLocked();
if (curMethod != null) {
curMethod.canStartStylusHandwriting(requestId.getAsInt());
}
} finally {
Binder.restoreCallingIdentity(ident);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
try {
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#startStylusHandwriting");
int uid = Binder.getCallingUid();
synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
return;
}
if (!hasSupportedStylusLocked()) {
Slog.w(TAG, "No supported Stylus hardware found on device. Ignoring"
+ " startStylusHandwriting()");
return;
}
final long ident = Binder.clearCallingIdentity();
try {
if (!canInteractWithImeLocked(uid, client, "startStylusHandwriting")) {
return;
}
if (!mBindingController.supportsStylusHandwriting()) {
Slog.w(TAG,
"Stylus HW unsupported by IME. Ignoring startStylusHandwriting()");
return;
}
final OptionalInt requestId = mHwController.getCurrentRequestId();
if (!requestId.isPresent()) {
Slog.e(TAG, "Stylus handwriting was not initialized.");
return;
}
if (!mHwController.isStylusGestureOngoing()) {
Slog.e(TAG,
"There is no ongoing stylus gesture to start stylus handwriting.");
return;
}
if (DEBUG) Slog.v(TAG, "Client requesting Stylus Handwriting to be started");
final IInputMethodInvoker curMethod = getCurMethodLocked();
if (curMethod != null) {
curMethod.canStartStylusHandwriting(requestId.getAsInt());
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
@@ -4382,6 +4400,144 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
}
private void registerDeviceListenerAndCheckStylusSupport() {
final InputManager im = mContext.getSystemService(InputManager.class);
final IntArray stylusIds = getStylusInputDeviceIds(im);
if (stylusIds.size() > 0) {
synchronized (ImfLock.class) {
mStylusIds = new IntArray();
mStylusIds.addAll(stylusIds);
}
}
im.registerInputDeviceListener(new InputManager.InputDeviceListener() {
@Override
public void onInputDeviceAdded(int deviceId) {
if (isStylusDevice(im.getInputDevice(deviceId))) {
add(deviceId);
}
}
@Override
public void onInputDeviceRemoved(int deviceId) {
remove(deviceId);
}
@Override
public void onInputDeviceChanged(int deviceId) {
if (isStylusDevice(im.getInputDevice(deviceId))) {
add(deviceId);
} else {
remove(deviceId);
}
}
private void add(int deviceId) {
synchronized (ImfLock.class) {
if (mStylusIds == null) {
mStylusIds = new IntArray();
} else if (mStylusIds.indexOf(deviceId) != -1) {
return;
}
Slog.d(TAG, "New Stylus device " + deviceId + " added.");
mStylusIds.add(deviceId);
// a new Stylus is detected. If IME supports handwriting and we don't have
// handwriting initialized, lets do it now.
if (!mHwController.getCurrentRequestId().isPresent()
&& mMethodMap.get(getSelectedMethodIdLocked())
.supportsStylusHandwriting()) {
scheduleResetStylusHandwriting();
}
}
}
private void remove(int deviceId) {
synchronized (ImfLock.class) {
if (mStylusIds == null || mStylusIds.size() == 0) {
return;
}
if (mStylusIds.indexOf(deviceId) != -1) {
mStylusIds.remove(deviceId);
Slog.d(TAG, "Stylus device " + deviceId + " removed.");
}
if (mStylusIds.size() == 0) {
mHwController.reset();
}
}
}
}, mHandler);
}
private static boolean isStylusDevice(InputDevice inputDevice) {
return inputDevice.supportsSource(InputDevice.SOURCE_STYLUS)
|| inputDevice.supportsSource(InputDevice.SOURCE_BLUETOOTH_STYLUS);
}
@GuardedBy("ImfLock.class")
private boolean hasSupportedStylusLocked() {
return mStylusIds != null && mStylusIds.size() != 0;
}
/**
* Helper method that adds a virtual stylus id for next handwriting session test if
* a stylus deviceId is not already registered on device.
*/
@BinderThread
@RequiresPermission(Manifest.permission.INJECT_EVENTS)
@Override
public void addVirtualStylusIdForTestSession(IInputMethodClient client) {
mContext.enforceCallingPermission(
Manifest.permission.INJECT_EVENTS,
"Using addVirtualStylusIdForTestSession() requires INJECT_EVENTS.");
int uid = Binder.getCallingUid();
synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
return;
}
final long ident = Binder.clearCallingIdentity();
try {
if (!canInteractWithImeLocked(uid, client, "addVirtualStylusIdForTestSession")) {
return;
}
if (!mBindingController.supportsStylusHandwriting()) {
Slog.w(TAG, "Stylus HW unsupported by IME. Ignoring addVirtualStylusId()");
return;
}
if (DEBUG) Slog.v(TAG, "Adding virtual stylus id for session");
if (mStylusIds == null) {
mStylusIds = new IntArray();
}
mStylusIds.add(VIRTUAL_STYLUS_ID_FOR_TEST);
scheduleResetStylusHandwriting();
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
@GuardedBy("ImfLock.class")
private void removeVirtualStylusIdForTestSessionLocked() {
int index;
if ((index = mStylusIds.indexOf(VIRTUAL_STYLUS_ID_FOR_TEST)) != -1) {
mStylusIds.remove(index);
}
}
private static IntArray getStylusInputDeviceIds(InputManager im) {
IntArray stylusIds = new IntArray();
for (int id : im.getInputDeviceIds()) {
if (!im.isInputDeviceEnabled(id)) {
continue;
}
InputDevice inputDevice = im.getInputDevice(id);
if (isStylusDevice(inputDevice)) {
stylusIds.add(id);
}
}
return stylusIds;
}
/**
* Starting point for dumping the IME tracing information in proto format.
*
@@ -4562,6 +4718,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
Slog.w(TAG, "IME requested to finish handwriting with a mismatched requestId: "
+ requestId);
}
removeVirtualStylusIdForTestSessionLocked();
scheduleResetStylusHandwriting();
}
}
@@ -4795,7 +4952,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_RESET_HANDWRITING: {
synchronized (ImfLock.class) {
if (mBindingController.supportsStylusHandwriting()
&& getCurMethodLocked() != null) {
&& getCurMethodLocked() != null && hasSupportedStylusLocked()) {
Slog.d(TAG, "Initializing Handwriting Spy");
mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
} else {
mHwController.reset();
@@ -5673,6 +5831,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
p.println(" mSettingsObserver=" + mSettingsObserver);
p.println(" mImeHiddenByDisplayPolicy=" + mImeHiddenByDisplayPolicy);
p.println(" mStylusIds=" + (mStylusIds != null
? Arrays.toString(mStylusIds.toArray()) : ""));
p.println(" mSwitchingController:");
mSwitchingController.dump(p);
p.println(" mSettings:");