Loading core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -21098,6 +21098,7 @@ package android.inputmethodservice { method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface(); method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); method public boolean onGenericMotionEvent(android.view.MotionEvent); method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent); method public boolean onTrackballEvent(android.view.MotionEvent); } Loading @@ -21115,6 +21116,7 @@ package android.inputmethodservice { method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback); method public boolean isEnabled(); method public boolean isRevoked(); method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent); method public void revokeSelf(); method public void setEnabled(boolean); } core/java/android/inputmethodservice/AbstractInputMethodService.java +17 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.inputmethodservice; import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT; import android.annotation.FlaggedApi; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -193,6 +196,12 @@ public abstract class AbstractInputMethodService extends WindowProviderService } } @FlaggedApi(FLAG_VERIFY_KEY_EVENT) @Override public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { return AbstractInputMethodService.this.onShouldVerifyKeyEvent(event); } /** * Take care of dispatching incoming trackball events to the appropriate * callbacks on the service, and tell the client when this is done. Loading Loading @@ -308,6 +317,14 @@ public abstract class AbstractInputMethodService extends WindowProviderService return false; } /** * @see InputMethodService#onShouldVerifyKeyEvent(KeyEvent) */ @FlaggedApi(FLAG_VERIFY_KEY_EVENT) public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { return false; } /** @hide */ @Override public final int getWindowType() { Loading core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +41 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,16 @@ package android.inputmethodservice; import static android.view.inputmethod.Flags.verifyKeyEvent; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Bundle; import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; import android.view.InputChannel; Loading @@ -41,6 +45,8 @@ import com.android.internal.inputmethod.IRemoteInputConnection; import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; import java.util.Objects; class IInputMethodSessionWrapper extends IInputMethodSession.Stub implements HandlerCaller.Callback { private static final String TAG = "InputMethodWrapper"; Loading @@ -56,6 +62,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub private static final int DO_REMOVE_IME_SURFACE = 130; private static final int DO_FINISH_INPUT = 140; private static final int DO_INVALIDATE_INPUT = 150; private final Context mContext; @UnsupportedAppUsage Loading @@ -66,6 +73,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub public IInputMethodSessionWrapper(Context context, InputMethodSession inputMethodSession, InputChannel channel) { mContext = context; mCaller = new HandlerCaller(context, null, this, true /*asyncHandler*/); mInputMethodSession = inputMethodSession; Loading Loading @@ -233,6 +241,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } private final class ImeInputEventReceiver extends InputEventReceiver implements InputMethodSession.EventCallback { // Time after which a KeyEvent is invalid private static final long KEY_EVENT_ALLOW_PERIOD_MS = 100L; private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>(); public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) { Loading @@ -247,10 +257,23 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub return; } if (event instanceof KeyEvent keyEvent && needsVerification(keyEvent)) { // any KeyEvent with modifiers (e.g. Ctrl/Alt/Fn) must be verified that // they originated from system. InputManager im = mContext.getSystemService(InputManager.class); Objects.requireNonNull(im); final long age = SystemClock.uptimeMillis() - keyEvent.getEventTime(); if (age >= KEY_EVENT_ALLOW_PERIOD_MS && im.verifyInputEvent(keyEvent) == null) { Log.w(TAG, "Unverified or Invalid KeyEvent injected into IME. Dropping " + keyEvent); finishInputEvent(event, false /* handled */); return; } } final int seq = event.getSequenceNumber(); mPendingEvents.put(seq, event); if (event instanceof KeyEvent) { KeyEvent keyEvent = (KeyEvent)event; if (event instanceof KeyEvent keyEvent) { mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this); } else { MotionEvent motionEvent = (MotionEvent)event; Loading @@ -271,5 +294,21 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub finishInputEvent(event, handled); } } private boolean hasKeyModifiers(KeyEvent event) { if (event.hasNoModifiers()) { return false; } return event.hasModifiers(KeyEvent.META_CTRL_ON) || event.hasModifiers(KeyEvent.META_ALT_ON) || event.hasModifiers(KeyEvent.KEYCODE_FUNCTION); } private boolean needsVerification(KeyEvent event) { //TODO(b/331730488): Handle a11y events as well. return verifyKeyEvent() && (hasKeyModifiers(event) || mInputMethodSession.onShouldVerifyKeyEvent(event)); } } } core/java/android/inputmethodservice/InputMethodService.java +18 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECT import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED; import static android.view.inputmethod.Flags.FLAG_CONNECTIONLESS_HANDWRITING; import static android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API; import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT; import static android.view.inputmethod.Flags.ctrlShiftShortcut; import static android.view.inputmethod.Flags.predictiveBackIme; Loading Loading @@ -3776,6 +3777,23 @@ public class InputMethodService extends AbstractInputMethodService { return doMovementKey(keyCode, event, MOVEMENT_DOWN); } /** * Received by the IME before dispatch to {@link #onKeyDown(int, KeyEvent)} to let the system * know if the {@link KeyEvent} needs to be verified that it originated from the system. * {@link KeyEvent}s may originate from outside of the system and any sensitive keys should be * marked for verification. One example of this could be using key shortcuts for switching to * another IME. * * @param keyEvent the event that may need verification. * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch, * {@code false} otherwise. */ @FlaggedApi(FLAG_VERIFY_KEY_EVENT) @Override public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent keyEvent) { return false; } /** * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle Loading core/java/android/view/inputmethod/InputMethodSession.java +18 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.os.Bundle; Loading Loading @@ -124,6 +125,23 @@ public interface InputMethodSession { */ public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback); /** * Received by the IME before dispatch to {@link InputMethodService#onKeyDown(int, KeyEvent)} * to let the system know if the {@link KeyEvent} needs to be verified that it originated from * the system. {@link KeyEvent}s may originate from outside of the system and any sensitive keys * should be marked for verification. One example of this could be using key shortcuts for * switching to another IME. * * @param event the event that may need verification. * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch, * {@code false} otherwise. * * @hide */ default boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { return false; } /** * This method is called when there is a track ball event. * Loading Loading
core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -21098,6 +21098,7 @@ package android.inputmethodservice { method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface(); method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); method public boolean onGenericMotionEvent(android.view.MotionEvent); method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent); method public boolean onTrackballEvent(android.view.MotionEvent); } Loading @@ -21115,6 +21116,7 @@ package android.inputmethodservice { method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback); method public boolean isEnabled(); method public boolean isRevoked(); method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent); method public void revokeSelf(); method public void setEnabled(boolean); }
core/java/android/inputmethodservice/AbstractInputMethodService.java +17 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.inputmethodservice; import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT; import android.annotation.FlaggedApi; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -193,6 +196,12 @@ public abstract class AbstractInputMethodService extends WindowProviderService } } @FlaggedApi(FLAG_VERIFY_KEY_EVENT) @Override public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { return AbstractInputMethodService.this.onShouldVerifyKeyEvent(event); } /** * Take care of dispatching incoming trackball events to the appropriate * callbacks on the service, and tell the client when this is done. Loading Loading @@ -308,6 +317,14 @@ public abstract class AbstractInputMethodService extends WindowProviderService return false; } /** * @see InputMethodService#onShouldVerifyKeyEvent(KeyEvent) */ @FlaggedApi(FLAG_VERIFY_KEY_EVENT) public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { return false; } /** @hide */ @Override public final int getWindowType() { Loading
core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +41 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,16 @@ package android.inputmethodservice; import static android.view.inputmethod.Flags.verifyKeyEvent; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Bundle; import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; import android.view.InputChannel; Loading @@ -41,6 +45,8 @@ import com.android.internal.inputmethod.IRemoteInputConnection; import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; import java.util.Objects; class IInputMethodSessionWrapper extends IInputMethodSession.Stub implements HandlerCaller.Callback { private static final String TAG = "InputMethodWrapper"; Loading @@ -56,6 +62,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub private static final int DO_REMOVE_IME_SURFACE = 130; private static final int DO_FINISH_INPUT = 140; private static final int DO_INVALIDATE_INPUT = 150; private final Context mContext; @UnsupportedAppUsage Loading @@ -66,6 +73,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub public IInputMethodSessionWrapper(Context context, InputMethodSession inputMethodSession, InputChannel channel) { mContext = context; mCaller = new HandlerCaller(context, null, this, true /*asyncHandler*/); mInputMethodSession = inputMethodSession; Loading Loading @@ -233,6 +241,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } private final class ImeInputEventReceiver extends InputEventReceiver implements InputMethodSession.EventCallback { // Time after which a KeyEvent is invalid private static final long KEY_EVENT_ALLOW_PERIOD_MS = 100L; private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>(); public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) { Loading @@ -247,10 +257,23 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub return; } if (event instanceof KeyEvent keyEvent && needsVerification(keyEvent)) { // any KeyEvent with modifiers (e.g. Ctrl/Alt/Fn) must be verified that // they originated from system. InputManager im = mContext.getSystemService(InputManager.class); Objects.requireNonNull(im); final long age = SystemClock.uptimeMillis() - keyEvent.getEventTime(); if (age >= KEY_EVENT_ALLOW_PERIOD_MS && im.verifyInputEvent(keyEvent) == null) { Log.w(TAG, "Unverified or Invalid KeyEvent injected into IME. Dropping " + keyEvent); finishInputEvent(event, false /* handled */); return; } } final int seq = event.getSequenceNumber(); mPendingEvents.put(seq, event); if (event instanceof KeyEvent) { KeyEvent keyEvent = (KeyEvent)event; if (event instanceof KeyEvent keyEvent) { mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this); } else { MotionEvent motionEvent = (MotionEvent)event; Loading @@ -271,5 +294,21 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub finishInputEvent(event, handled); } } private boolean hasKeyModifiers(KeyEvent event) { if (event.hasNoModifiers()) { return false; } return event.hasModifiers(KeyEvent.META_CTRL_ON) || event.hasModifiers(KeyEvent.META_ALT_ON) || event.hasModifiers(KeyEvent.KEYCODE_FUNCTION); } private boolean needsVerification(KeyEvent event) { //TODO(b/331730488): Handle a11y events as well. return verifyKeyEvent() && (hasKeyModifiers(event) || mInputMethodSession.onShouldVerifyKeyEvent(event)); } } }
core/java/android/inputmethodservice/InputMethodService.java +18 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECT import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED; import static android.view.inputmethod.Flags.FLAG_CONNECTIONLESS_HANDWRITING; import static android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API; import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT; import static android.view.inputmethod.Flags.ctrlShiftShortcut; import static android.view.inputmethod.Flags.predictiveBackIme; Loading Loading @@ -3776,6 +3777,23 @@ public class InputMethodService extends AbstractInputMethodService { return doMovementKey(keyCode, event, MOVEMENT_DOWN); } /** * Received by the IME before dispatch to {@link #onKeyDown(int, KeyEvent)} to let the system * know if the {@link KeyEvent} needs to be verified that it originated from the system. * {@link KeyEvent}s may originate from outside of the system and any sensitive keys should be * marked for verification. One example of this could be using key shortcuts for switching to * another IME. * * @param keyEvent the event that may need verification. * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch, * {@code false} otherwise. */ @FlaggedApi(FLAG_VERIFY_KEY_EVENT) @Override public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent keyEvent) { return false; } /** * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle Loading
core/java/android/view/inputmethod/InputMethodSession.java +18 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.os.Bundle; Loading Loading @@ -124,6 +125,23 @@ public interface InputMethodSession { */ public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback); /** * Received by the IME before dispatch to {@link InputMethodService#onKeyDown(int, KeyEvent)} * to let the system know if the {@link KeyEvent} needs to be verified that it originated from * the system. {@link KeyEvent}s may originate from outside of the system and any sensitive keys * should be marked for verification. One example of this could be using key shortcuts for * switching to another IME. * * @param event the event that may need verification. * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch, * {@code false} otherwise. * * @hide */ default boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { return false; } /** * This method is called when there is a track ball event. * Loading