summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java21
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java62
-rw-r--r--core/java/android/view/inputmethod/IInputMethodManagerInvoker.java11
-rw-r--r--core/java/android/view/inputmethod/InputMethod.java9
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java16
-rw-r--r--core/java/com/android/internal/inputmethod/IInputMethod.aidl2
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl6
-rw-r--r--services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java9
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java26
10 files changed, 154 insertions, 9 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index fb2c9e43497f..969a05c0a988 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3135,6 +3135,7 @@ package android.view.inputmethod {
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);
method public boolean isInputMethodPickerShown();
+ method @RequiresPermission("android.permission.TEST_INPUT_METHOD") public void setStylusWindowIdleTimeoutForTest(long);
field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
}
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index a87b1338339a..d23fb363df1c 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -17,6 +17,7 @@
package android.inputmethodservice;
import android.annotation.BinderThread;
+import android.annotation.DurationMillisLong;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -82,6 +83,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
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;
+ private static final int DO_SET_STYLUS_WINDOW_IDLE_TIMEOUT = 160;
final WeakReference<InputMethodServiceInternal> mTarget;
final Context mContext;
@@ -151,7 +153,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
final InputMethodServiceInternal target = mTarget.get();
switch (msg.what) {
case DO_DUMP: {
- SomeArgs args = (SomeArgs)msg.obj;
+ SomeArgs args = (SomeArgs) msg.obj;
if (isValid(inputMethod, target, "DO_DUMP")) {
final FileDescriptor fd = (FileDescriptor) args.arg1;
final PrintWriter fout = (PrintWriter) args.arg2;
@@ -201,7 +203,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
return;
case DO_CREATE_SESSION: {
- SomeArgs args = (SomeArgs)msg.obj;
+ SomeArgs args = (SomeArgs) msg.obj;
if (isValid(inputMethod, target, "DO_CREATE_SESSION")) {
inputMethod.createSession(new InputMethodSessionCallbackWrapper(
mContext, (InputChannel) args.arg1,
@@ -216,7 +218,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
return;
case DO_SHOW_SOFT_INPUT: {
- final SomeArgs args = (SomeArgs)msg.obj;
+ final SomeArgs args = (SomeArgs) msg.obj;
if (isValid(inputMethod, target, "DO_SHOW_SOFT_INPUT")) {
inputMethod.showSoftInputWithToken(
msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1);
@@ -287,6 +289,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
return;
}
+ case DO_SET_STYLUS_WINDOW_IDLE_TIMEOUT: {
+ inputMethod.setStylusWindowIdleTimeoutForTest((long) msg.obj);
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -300,7 +306,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
if (target.getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
-
+
fout.println("Permission Denial: can't dump InputMethodManager from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
@@ -473,6 +479,13 @@ class IInputMethodWrapper extends IInputMethod.Stub
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_STYLUS_HANDWRITING_WINDOW));
}
+ @BinderThread
+ @Override
+ public void setStylusWindowIdleTimeoutForTest(@DurationMillisLong long timeout) {
+ mCaller.executeOrSendMessage(
+ mCaller.obtainMessageO(DO_SET_STYLUS_WINDOW_IDLE_TIMEOUT, timeout));
+ }
+
private static boolean isValid(InputMethod inputMethod, InputMethodServiceInternal target,
String msg) {
if (inputMethod != null && target != null && !target.isServiceDestroyed()) {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6cd542af3574..f92f8a328519 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -57,6 +57,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.AnyThread;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
+import android.annotation.DurationMillisLong;
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -363,6 +364,11 @@ public class InputMethodService extends AbstractInputMethodService {
STYLUS_HANDWRITING_IDLE_TIMEOUT_MS * 3;
/**
+ * Stylus idle-timeout after which stylus {@code InkWindow} will be removed.
+ */
+ private static final long STYLUS_WINDOW_IDLE_TIMEOUT_MILLIS = 5 * 60 * 1000; // 5 minutes.
+
+ /**
* A circular buffer of size MAX_EVENTS_BUFFER in case IME is taking too long to add ink view.
**/
private RingBuffer<MotionEvent> mPendingEvents;
@@ -372,6 +378,8 @@ public class InputMethodService extends AbstractInputMethodService {
private Runnable mImeSurfaceRemoverRunnable;
private Runnable mFinishHwRunnable;
private long mStylusHwSessionsTimeout = STYLUS_HANDWRITING_IDLE_TIMEOUT_MS;
+ private Runnable mStylusWindowIdleTimeoutRunnable;
+ private long mStylusWindowIdleTimeoutForTest;
/**
* Returns whether {@link InputMethodService} is responsible for rendering the back button and
@@ -1035,7 +1043,6 @@ public class InputMethodService extends AbstractInputMethodService {
mInkWindow = new InkWindow(mWindow.getContext());
mInkWindow.setToken(mToken);
}
- // TODO(b/243571274): set an idle-timeout after which InkWindow is removed.
mInkWindow.initOnly();
}
@@ -1059,6 +1066,15 @@ public class InputMethodService extends AbstractInputMethodService {
/**
* {@inheritDoc}
+ * @hide
+ */
+ @Override
+ public void setStylusWindowIdleTimeoutForTest(@DurationMillisLong long timeout) {
+ mStylusWindowIdleTimeoutForTest = timeout;
+ }
+
+ /**
+ * {@inheritDoc}
*/
@MainThread
@Override
@@ -2485,6 +2501,11 @@ public class InputMethodService extends AbstractInputMethodService {
});
}
}
+
+ // Create a stylus window idle-timeout after which InkWindow is removed.
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
+ scheduleStylusWindowIdleTimeout();
+ }
}
/**
@@ -2545,7 +2566,6 @@ 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);
@@ -2569,9 +2589,41 @@ public class InputMethodService extends AbstractInputMethodService {
}
private void removeHandwritingInkWindow() {
- mInkWindow.hide(true /* remove */);
- mInkWindow.destroy();
- mInkWindow = null;
+ cancelStylusWindowIdleTimeout();
+ mOnPreparedStylusHwCalled = false;
+ mStylusWindowIdleTimeoutRunnable = null;
+ if (mInkWindow != null) {
+ mInkWindow.hide(true /* remove */);
+ mInkWindow.destroy();
+ mInkWindow = null;
+ }
+ }
+
+ private void cancelStylusWindowIdleTimeout() {
+ if (mStylusWindowIdleTimeoutRunnable != null && mHandler != null) {
+ mHandler.removeCallbacks(mStylusWindowIdleTimeoutRunnable);
+ }
+ }
+
+ private void scheduleStylusWindowIdleTimeout() {
+ if (mHandler == null) {
+ return;
+ }
+ cancelStylusWindowIdleTimeout();
+ long timeout = (mStylusWindowIdleTimeoutForTest > 0)
+ ? mStylusWindowIdleTimeoutForTest : STYLUS_WINDOW_IDLE_TIMEOUT_MILLIS;
+ mHandler.postDelayed(getStylusWindowIdleTimeoutRunnable(), timeout);
+ }
+
+ private Runnable getStylusWindowIdleTimeoutRunnable() {
+ if (mStylusWindowIdleTimeoutRunnable == null) {
+ mStylusWindowIdleTimeoutRunnable = () -> {
+ removeHandwritingInkWindow();
+ mStylusWindowIdleTimeoutRunnable = null;
+ };
+ }
+
+ return mStylusWindowIdleTimeoutRunnable;
}
/**
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerInvoker.java
index 429b0b80aec3..70fd8cf114d5 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerInvoker.java
@@ -17,6 +17,7 @@
package android.view.inputmethod;
import android.annotation.AnyThread;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -264,4 +265,14 @@ final class IInputMethodManagerInvoker {
throw e.rethrowFromSystemServer();
}
}
+
+ @AnyThread
+ void setStylusWindowIdleTimeoutForTest(
+ IInputMethodClient client, @DurationMillisLong long timeout) {
+ try {
+ mTarget.setStylusWindowIdleTimeoutForTest(client, timeout);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 978bfc7af60d..4d5a17d92f11 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.annotation.DurationMillisLong;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -417,4 +418,12 @@ public interface InputMethod {
default void removeStylusHandwritingWindow() {
// intentionally empty
}
+
+ /**
+ * Set a stylus idle-timeout after which handwriting {@code InkWindow} will be removed.
+ * @hide
+ */
+ default void setStylusWindowIdleTimeoutForTest(@DurationMillisLong long timeout) {
+ // intentionally empty
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7794b7c90303..c01b4055293b 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -36,8 +36,10 @@ import static com.android.internal.inputmethod.StartInputReason.BOUND_TO_IMMS;
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION;
+import android.Manifest;
import android.annotation.DisplayContext;
import android.annotation.DrawableRes;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
@@ -2576,6 +2578,20 @@ public final class InputMethodManager {
}
/**
+ * Set a stylus idle-timeout after which handwriting {@code InkWindow} will be removed.
+ * <p> This API is for tests only.</p>
+ * @param timeout to set in milliseconds. To reset to default, use a value <= zero.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
+ @TestApi
+ public void setStylusWindowIdleTimeoutForTest(@DurationMillisLong long timeout) {
+ synchronized (mH) {
+ mServiceInvoker.setStylusWindowIdleTimeoutForTest(mClient, timeout);
+ }
+ }
+
+ /**
* 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.
*
diff --git a/core/java/com/android/internal/inputmethod/IInputMethod.aidl b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
index 9182d1dc56bf..c62fba9fb9b8 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethod.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
@@ -87,4 +87,6 @@ oneway interface IInputMethod {
void finishStylusHandwriting();
void removeStylusHandwritingWindow();
+
+ void setStylusWindowIdleTimeoutForTest(long timeout);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 9471faec8ea1..83660566b0d9 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -144,4 +144,10 @@ interface IInputMethodManager {
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INJECT_EVENTS)")
void addVirtualStylusIdForTestSession(in IInputMethodClient client);
+
+ /** Set a stylus idle-timeout after which handwriting {@code InkWindow} will be removed. */
+ @EnforcePermission("TEST_INPUT_METHOD")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ + "android.Manifest.permission.TEST_INPUT_METHOD)")
+ void setStylusWindowIdleTimeoutForTest(in IInputMethodClient client, long timeout);
}
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index 3e397468aa87..0810e3b1f928 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -286,4 +286,13 @@ final class IInputMethodInvoker {
logRemoteException(e);
}
}
+
+ @AnyThread
+ void setStylusWindowIdleTimeoutForTest(long timeout) {
+ try {
+ mTarget.setStylusWindowIdleTimeoutForTest(timeout);
+ } catch (RemoteException e) {
+ logRemoteException(e);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ed17b9ca3a47..75834ccde245 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -60,6 +60,7 @@ import android.annotation.AnyThread;
import android.annotation.BinderThread;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.DurationMillisLong;
import android.annotation.EnforcePermission;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -4463,6 +4464,31 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
}
+ /**
+ * Helper method to set a stylus idle-timeout after which handwriting {@code InkWindow}
+ * will be removed.
+ * @param timeout to set in milliseconds. To reset to default, use a value <= zero.
+ */
+ @BinderThread
+ @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
+ @Override
+ public void setStylusWindowIdleTimeoutForTest(
+ IInputMethodClient client, @DurationMillisLong long timeout) {
+ int uid = Binder.getCallingUid();
+ synchronized (ImfLock.class) {
+ if (!canInteractWithImeLocked(uid, client, "setStylusWindowIdleTimeoutForTest")) {
+ return;
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Setting stylus window idle timeout");
+ getCurMethodLocked().setStylusWindowIdleTimeoutForTest(timeout);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
@GuardedBy("ImfLock.class")
private void removeVirtualStylusIdForTestSessionLocked() {
removeStylusDeviceIdLocked(VIRTUAL_STYLUS_ID_FOR_TEST);