Remove inkWindow after stylus idle-timeout
After stylus hasnt been used for handwriting in last X minutes, remove the the stylus handwriting window. Bug: 243571274 Test: StylusHandwritingTest Change-Id: I641be63e028ea9cbfd882ce318d30aad71fd8a4e
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
@@ -362,6 +363,11 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
private static final long STYLUS_HANDWRITING_IDLE_TIMEOUT_MAX_MS =
|
||||
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.
|
||||
**/
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -1057,6 +1064,15 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
InputMethodService.this.removeStylusHandwritingWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void setStylusWindowIdleTimeoutForTest(@DurationMillisLong long timeout) {
|
||||
mStylusWindowIdleTimeoutForTest = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -2575,6 +2577,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.
|
||||
|
||||
@@ -87,4 +87,6 @@ oneway interface IInputMethod {
|
||||
void finishStylusHandwriting();
|
||||
|
||||
void removeStylusHandwritingWindow();
|
||||
|
||||
void setStylusWindowIdleTimeoutForTest(long timeout);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -286,4 +286,13 @@ final class IInputMethodInvoker {
|
||||
logRemoteException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
void setStylusWindowIdleTimeoutForTest(long timeout) {
|
||||
try {
|
||||
mTarget.setStylusWindowIdleTimeoutForTest(timeout);
|
||||
} catch (RemoteException e) {
|
||||
logRemoteException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user