Loading core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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); Loading core/java/android/view/inputmethod/IInputMethodManagerInvoker.java +9 −0 Original line number Diff line number Diff line Loading @@ -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(); } } } core/java/android/view/inputmethod/InputMethodManager.java +11 −0 Original line number Diff line number Diff line Loading @@ -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. Loading core/java/com/android/internal/view/IInputMethodManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -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); } services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +190 −30 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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"; Loading Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -3369,12 +3377,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public void startStylusHandwriting(IInputMethodClient client) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.startStylusHandwriting"); try { ImeTracing.getInstance().triggerManagerServiceDump( "InputMethodManagerService#startStylusHandwriting"); int uid = Binder.getCallingUid(); synchronized (ImfLock.class) { if (!calledFromValidUserLocked()) { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return; } if (!hasSupportedStylusLocked()) { Slog.w(TAG, "No supported Stylus hardware found on device. Ignoring" + " startStylusHandwriting()"); return; } final long ident = Binder.clearCallingIdentity(); Loading @@ -3383,16 +3396,19 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return; } if (!mBindingController.supportsStylusHandwriting()) { Slog.w(TAG, "Stylus HW unsupported by IME. Ignoring startStylusHandwriting()"); 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."); 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"); Loading @@ -3402,9 +3418,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } finally { Binder.restoreCallingIdentity(ident); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } @BinderThread Loading Loading @@ -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. * Loading Loading @@ -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(); } } Loading Loading @@ -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(); Loading Loading @@ -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:"); Loading Loading
core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
core/java/android/view/inputmethod/IInputMethodManagerInvoker.java +9 −0 Original line number Diff line number Diff line Loading @@ -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(); } } }
core/java/android/view/inputmethod/InputMethodManager.java +11 −0 Original line number Diff line number Diff line Loading @@ -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. Loading
core/java/com/android/internal/view/IInputMethodManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -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); }
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +190 −30 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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"; Loading Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -3369,12 +3377,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public void startStylusHandwriting(IInputMethodClient client) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.startStylusHandwriting"); try { ImeTracing.getInstance().triggerManagerServiceDump( "InputMethodManagerService#startStylusHandwriting"); int uid = Binder.getCallingUid(); synchronized (ImfLock.class) { if (!calledFromValidUserLocked()) { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return; } if (!hasSupportedStylusLocked()) { Slog.w(TAG, "No supported Stylus hardware found on device. Ignoring" + " startStylusHandwriting()"); return; } final long ident = Binder.clearCallingIdentity(); Loading @@ -3383,16 +3396,19 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return; } if (!mBindingController.supportsStylusHandwriting()) { Slog.w(TAG, "Stylus HW unsupported by IME. Ignoring startStylusHandwriting()"); 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."); 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"); Loading @@ -3402,9 +3418,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } finally { Binder.restoreCallingIdentity(ident); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } @BinderThread Loading Loading @@ -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. * Loading Loading @@ -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(); } } Loading Loading @@ -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(); Loading Loading @@ -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:"); Loading