diff options
| author | 2022-08-11 18:32:47 +0000 | |
|---|---|---|
| committer | 2022-08-24 00:24:04 +0000 | |
| commit | f092a7cb23aa94d9250948de0e936f155d7ea1cd (patch) | |
| tree | f0f6889a54c901357520d4d9cc24f725ee7685ee | |
| parent | b40e48cd51dc771da422515e23821e60bc67b483 (diff) | |
Improve handwriting Ink window lifetime
1. When the system removes the last known stylus device
and has no other stylus available, remove the Ink window.
2. Create InkWindow only if the device+IME combination supports
handwriting and the stylus is being used.
Bug: 243571274
Bug: 239121683
Bug: 210039666
Test: atest StylusHandwritingTest
Change-Id: Icd3eea91fe144cff7100d3ecf19191c064c0d196
7 files changed, 129 insertions, 54 deletions
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 3d593872757d..05daf63fdd5d 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<InputMethodServiceInternal> 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 c2027b136f0e..48b9b8869cae 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,12 +1026,24 @@ 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 */ @@ -1047,6 +1054,15 @@ public class InputMethodService extends AbstractInputMethodService { /** * {@inheritDoc} + * @hide + */ + @Override + public void removeStylusHandwritingWindow() { + InputMethodService.this.removeStylusHandwritingWindow(); + } + + /** + * {@inheritDoc} */ @MainThread @Override @@ -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); @@ -2519,6 +2536,27 @@ public class InputMethodService extends AbstractInputMethodService { } /** + * 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 bfe6ae6447d0..978bfc7af60d 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 5db2e84845f5..9182d1dc56bf 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 eb73234549c9..3e397468aa87 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 b63592c2fedb..23ea39a3b022 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 23f437392d2b..7bd835c73749 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 @@ -2734,6 +2735,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @AnyThread + void scheduleRemoveStylusHandwritingWindow() { + mHandler.obtainMessage(MSG_REMOVE_HANDWRITING_WINDOW).sendToTarget(); + } + + @AnyThread void scheduleNotifyImeUidToAudioService(int uid) { mHandler.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE); mHandler.obtainMessage(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid, 0 /* unused */) @@ -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; } |