diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 3d593872757d1..05daf63fdd5d6 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -81,6 +81,7 @@ class IInputMethodWrapper extends IInputMethod.Stub private static final int DO_INIT_INK_WINDOW = 120; private static final int DO_FINISH_STYLUS_HANDWRITING = 130; private static final int DO_UPDATE_TOOL_TYPE = 140; + private static final int DO_REMOVE_STYLUS_HANDWRITING_WINDOW = 150; final WeakReference mTarget; final Context mContext; @@ -254,6 +255,10 @@ class IInputMethodWrapper extends IInputMethod.Stub inputMethod.finishStylusHandwriting(); return; } + case DO_REMOVE_STYLUS_HANDWRITING_WINDOW: { + inputMethod.removeStylusHandwritingWindow(); + return; + } } Log.w(TAG, "Unhandled message code: " + msg.what); @@ -434,4 +439,10 @@ class IInputMethodWrapper extends IInputMethod.Stub public void finishStylusHandwriting() { mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_STYLUS_HANDWRITING)); } + + @BinderThread + @Override + public void removeStylusHandwritingWindow() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_STYLUS_HANDWRITING_WINDOW)); + } } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index c2027b136f0e4..48b9b8869caed 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -621,7 +621,7 @@ public class InputMethodService extends AbstractInputMethodService { private boolean mDestroyed; private boolean mOnPreparedStylusHwCalled; - /** Stylus handwriting Ink window. */ + /** Stylus handwriting Ink window. */ private InkWindow mInkWindow; /** @@ -708,9 +708,6 @@ public class InputMethodService extends AbstractInputMethodService { mConfigTracker.onInitialize(params.configChanges); mPrivOps.set(params.privilegedOperations); InputMethodPrivilegedOperationsRegistry.put(params.token, mPrivOps); - if (params.stylusHandWritingSupported) { - mInkWindow = new InkWindow(mWindow.getContext()); - } mNavigationBarController.onNavButtonFlagsChanged(params.navigationBarFlags); attachToken(params.token); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); @@ -744,9 +741,6 @@ public class InputMethodService extends AbstractInputMethodService { attachToWindowToken(token); mToken = token; mWindow.setToken(token); - if (mInkWindow != null) { - mInkWindow.setToken(token); - } } /** @@ -785,7 +779,7 @@ public class InputMethodService extends AbstractInputMethodService { mInputConnection = null; // free-up cached InkWindow surface on detaching from current client. if (mInkWindow != null) { - mInkWindow.hide(true /* remove */); + removeHandwritingInkWindow(); } } @@ -972,6 +966,7 @@ public class InputMethodService extends AbstractInputMethodService { Log.d(TAG, "Input should have started before starting Stylus handwriting."); return; } + maybeCreateInkWindow(); if (!mOnPreparedStylusHwCalled) { // prepare hasn't been called by Stylus HOVER. onPrepareStylusHandwriting(); @@ -1031,11 +1026,23 @@ public class InputMethodService extends AbstractInputMethodService { */ @Override public void initInkWindow() { + maybeCreateInkWindow(); mInkWindow.initOnly(); onPrepareStylusHandwriting(); mOnPreparedStylusHwCalled = true; } + /** + * Create and attach token to Ink window if it wasn't already created. + */ + private void maybeCreateInkWindow() { + if (mInkWindow == null) { + mInkWindow = new InkWindow(mWindow.getContext()); + mInkWindow.setToken(mToken); + } + // TODO(b/243571274): set an idle-timeout after which InkWindow is removed. + } + /** * {@inheritDoc} * @hide @@ -1045,6 +1052,15 @@ public class InputMethodService extends AbstractInputMethodService { InputMethodService.this.finishStylusHandwriting(); } + /** + * {@inheritDoc} + * @hide + */ + @Override + public void removeStylusHandwritingWindow() { + InputMethodService.this.removeStylusHandwritingWindow(); + } + /** * {@inheritDoc} */ @@ -2511,6 +2527,7 @@ public class InputMethodService extends AbstractInputMethodService { mHandwritingEventReceiver.dispose(); mHandwritingEventReceiver = null; + // TODO(b/243571274): set an idle-timeout after which InkWindow is removed. mInkWindow.hide(false /* remove */); mPrivOps.resetStylusHandwriting(requestId); @@ -2518,6 +2535,27 @@ public class InputMethodService extends AbstractInputMethodService { onFinishStylusHandwriting(); } + /** + * Remove Stylus handwriting window. + * Typically, this is called when {@link InkWindow} should no longer be holding a surface in + * memory. + */ + private void removeStylusHandwritingWindow() { + if (mInkWindow != null) { + if (mHandwritingRequestId.isPresent()) { + // if handwriting session is still ongoing. This shouldn't happen. + finishStylusHandwriting(); + } + removeHandwritingInkWindow(); + } + } + + private void removeHandwritingInkWindow() { + mInkWindow.hide(true /* remove */); + mInkWindow.destroy(); + mInkWindow = null; + } + /** * Sets the duration after which an ongoing stylus handwriting session that hasn't received new * {@link MotionEvent}s will time out and {@link #finishStylusHandwriting()} will be called. diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index bfe6ae6447d0e..978bfc7af60dd 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -410,4 +410,11 @@ public interface InputMethod { // intentionally empty } + /** + * Remove stylus handwriting window. + * @hide + */ + default void removeStylusHandwritingWindow() { + // intentionally empty + } } diff --git a/core/java/com/android/internal/inputmethod/IInputMethod.aidl b/core/java/com/android/internal/inputmethod/IInputMethod.aidl index 5db2e84845f50..9182d1dc56bf1 100644 --- a/core/java/com/android/internal/inputmethod/IInputMethod.aidl +++ b/core/java/com/android/internal/inputmethod/IInputMethod.aidl @@ -40,7 +40,6 @@ oneway interface IInputMethod { IBinder token; IInputMethodPrivilegedOperations privilegedOperations; int configChanges; - boolean stylusHandWritingSupported; int navigationBarFlags; } @@ -86,4 +85,6 @@ oneway interface IInputMethod { void initInkWindow(); void finishStylusHandwriting(); + + void removeStylusHandwritingWindow(); } diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java index eb73234549c92..3e397468aa875 100644 --- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java +++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java @@ -109,13 +109,11 @@ final class IInputMethodInvoker { @AnyThread void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privilegedOperations, - int configChanges, boolean stylusHandWritingSupported, - @InputMethodNavButtonFlags int navigationBarFlags) { + int configChanges, @InputMethodNavButtonFlags int navigationBarFlags) { final IInputMethod.InitParams params = new IInputMethod.InitParams(); params.token = token; params.privilegedOperations = privilegedOperations; params.configChanges = configChanges; - params.stylusHandWritingSupported = stylusHandWritingSupported; params.navigationBarFlags = navigationBarFlags; try { mTarget.initializeInternal(params); @@ -279,4 +277,13 @@ final class IInputMethodInvoker { logRemoteException(e); } } + + @AnyThread + void removeStylusHandwritingWindow() { + try { + mTarget.removeStylusHandwritingWindow(); + } catch (RemoteException e) { + logRemoteException(e); + } + } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index b63592c2fedbe..23ea39a3b022f 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -286,8 +286,7 @@ final class InputMethodBindingController { if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken); final InputMethodInfo info = mMethodMap.get(mSelectedMethodId); mSupportsStylusHw = info.supportsStylusHandwriting(); - mService.initializeImeLocked(mCurMethod, mCurToken, info.getConfigChanges(), - mSupportsStylusHw); + mService.initializeImeLocked(mCurMethod, mCurToken, info.getConfigChanges()); mService.scheduleNotifyImeUidToAudioService(mCurMethodUid); mService.reRequestCurrentClientSessionLocked(); mService.performOnCreateInlineSuggestionsRequestLocked(); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 23f437392d2b3..7bd835c737497 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -246,6 +246,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub private static final int MSG_RESET_HANDWRITING = 1090; private static final int MSG_START_HANDWRITING = 1100; private static final int MSG_FINISH_HANDWRITING = 1110; + private static final int MSG_REMOVE_HANDWRITING_WINDOW = 1120; private static final int MSG_SET_INTERACTIVE = 3030; @@ -2719,13 +2720,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") void initializeImeLocked(@NonNull IInputMethodInvoker inputMethod, @NonNull IBinder token, - @android.content.pm.ActivityInfo.Config int configChanges, boolean supportStylusHw) { + @android.content.pm.ActivityInfo.Config int configChanges) { if (DEBUG) { Slog.v(TAG, "Sending attach of token: " + token + " for display: " + mCurTokenDisplayId); } inputMethod.initializeInternal(token, new InputMethodPrivilegedOperationsImpl(this, token), - configChanges, supportStylusHw, getInputMethodNavButtonFlagsLocked()); + configChanges, getInputMethodNavButtonFlagsLocked()); } @AnyThread @@ -2733,6 +2734,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub mHandler.obtainMessage(MSG_RESET_HANDWRITING).sendToTarget(); } + @AnyThread + void scheduleRemoveStylusHandwritingWindow() { + mHandler.obtainMessage(MSG_REMOVE_HANDWRITING_WINDOW).sendToTarget(); + } + @AnyThread void scheduleNotifyImeUidToAudioService(int uid) { mHandler.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE); @@ -4363,40 +4369,50 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub 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(); - } + addStylusDeviceIdLocked(deviceId); } } 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(); - } + removeStylusDeviceIdLocked(deviceId); } } }, mHandler); } + private void addStylusDeviceIdLocked(int deviceId) { + if (mStylusIds == null) { + mStylusIds = new IntArray(); + } else if (mStylusIds.indexOf(deviceId) != -1) { + return; + } + Slog.d(TAG, "New Stylus deviceId" + 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() + && mBindingController.supportsStylusHandwriting()) { + scheduleResetStylusHandwriting(); + } + } + + private void removeStylusDeviceIdLocked(int deviceId) { + if (mStylusIds == null || mStylusIds.size() == 0) { + return; + } + int index; + if ((index = mStylusIds.indexOf(deviceId)) != -1) { + mStylusIds.remove(index); + Slog.d(TAG, "Stylus deviceId: " + deviceId + " removed."); + } + if (mStylusIds.size() == 0) { + // no more supported stylus(es) in system. + mHwController.reset(); + scheduleRemoveStylusHandwritingWindow(); + } + } + private static boolean isStylusDevice(InputDevice inputDevice) { return inputDevice.supportsSource(InputDevice.SOURCE_STYLUS) || inputDevice.supportsSource(InputDevice.SOURCE_BLUETOOTH_STYLUS); @@ -4422,17 +4438,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } final long ident = Binder.clearCallingIdentity(); try { - 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(); + addStylusDeviceIdLocked(VIRTUAL_STYLUS_ID_FOR_TEST); } finally { Binder.restoreCallingIdentity(ident); } @@ -4441,10 +4448,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") private void removeVirtualStylusIdForTestSessionLocked() { - int index; - if ((index = mStylusIds.indexOf(VIRTUAL_STYLUS_ID_FOR_TEST)) != -1) { - mStylusIds.remove(index); - } + removeStylusDeviceIdLocked(VIRTUAL_STYLUS_ID_FOR_TEST); } private static IntArray getStylusInputDeviceIds(InputManager im) { @@ -4922,6 +4926,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } return true; + case MSG_REMOVE_HANDWRITING_WINDOW: + synchronized (ImfLock.class) { + IInputMethodInvoker curMethod = getCurMethodLocked(); + if (curMethod != null) { + curMethod.removeStylusHandwritingWindow(); + } + } + return true; } return false; }