Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -18820,6 +18820,7 @@ package android.inputmethodservice { method public void onStartInput(android.view.inputmethod.EditorInfo, boolean); method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean); method public boolean onStartStylusHandwriting(); method public void onStylusHandwritingMotionEvent(@NonNull android.view.MotionEvent); method public void onUnbindInput(); method @Deprecated public void onUpdateCursor(android.graphics.Rect); method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo); core/java/android/inputmethodservice/InkWindow.java +78 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.content.Context; import android.os.IBinder; import android.util.Slog; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; import com.android.internal.policy.PhoneWindow; Loading @@ -40,6 +42,9 @@ final class InkWindow extends PhoneWindow { private final WindowManager mWindowManager; private boolean mIsViewAdded; private View mInkView; private InkVisibilityListener mInkViewVisibilityListener; private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener; public InkWindow(@NonNull Context context) { super(context); Loading Loading @@ -102,4 +107,77 @@ final class InkWindow extends PhoneWindow { lp.token = token; setAttributes(lp); } @Override public void addContentView(View view, ViewGroup.LayoutParams params) { if (mInkView == null) { mInkView = view; } else if (mInkView != view) { throw new IllegalStateException("Only one Child Inking view is permitted."); } super.addContentView(view, params); initInkViewVisibilityListener(); } @Override public void setContentView(View view, ViewGroup.LayoutParams params) { mInkView = view; super.setContentView(view, params); initInkViewVisibilityListener(); } @Override public void setContentView(View view) { mInkView = view; super.setContentView(view); initInkViewVisibilityListener(); } @Override public void clearContentView() { if (mGlobalLayoutListener != null && mInkView != null) { mInkView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener); } mGlobalLayoutListener = null; mInkView = null; super.clearContentView(); } /** * Listener used by InkWindow to time the dispatching of {@link MotionEvent}s to Ink view, once * it is visible to user. */ interface InkVisibilityListener { void onInkViewVisible(); } void setInkViewVisibilityListener(InkVisibilityListener listener) { mInkViewVisibilityListener = listener; initInkViewVisibilityListener(); } void initInkViewVisibilityListener() { if (mInkView == null || mInkViewVisibilityListener == null || mGlobalLayoutListener != null) { return; } mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (mInkView.isVisibleToUser()) { if (mInkViewVisibilityListener != null) { mInkViewVisibilityListener.onInkViewVisible(); } mInkView.getViewTreeObserver().removeOnGlobalLayoutListener(this); mGlobalLayoutListener = null; } } }; mInkView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener); } boolean isInkViewVisible() { return getDecorView().getVisibility() == View.VISIBLE && mInkView != null && mInkView.isVisibleToUser(); } } core/java/android/inputmethodservice/InputMethodService.java +45 −4 Original line number Diff line number Diff line Loading @@ -143,6 +143,7 @@ import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.InputMethodNavButtonFlags; import com.android.internal.inputmethod.InputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; import com.android.internal.util.RingBuffer; import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInputContext; import com.android.internal.view.InlineSuggestionsRequestInfo; Loading Loading @@ -333,6 +334,17 @@ public class InputMethodService extends AbstractInputMethodService { private static final String PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS = "persist.sys.ime.can_render_gestural_nav_buttons"; /** * Number of {@link MotionEvent} to buffer if IME is not ready with Ink view. * This number may be configured eventually based on device's touch sampling frequency. */ private static final int MAX_EVENTS_BUFFER = 500; /** * A circular buffer of size MAX_EVENTS_BUFFER in case IME is taking too long to add ink view. **/ private RingBuffer<MotionEvent> mPendingEvents; /** * Returns whether {@link InputMethodService} is responsible for rendering the back button and * the IME switcher button or not when the gestural navigation is enabled. Loading Loading @@ -954,7 +966,8 @@ public class InputMethodService extends AbstractInputMethodService { mInkWindow.show(); // deliver previous @param stylusEvents stylusEvents.forEach(mInkWindow.getDecorView()::dispatchTouchEvent); stylusEvents.forEach(InputMethodService.this::onStylusHandwritingMotionEvent); // create receiver for channel mHandwritingEventReceiver = new SimpleBatchedInputEventReceiver( channel, Loading @@ -963,11 +976,11 @@ public class InputMethodService extends AbstractInputMethodService { if (!(event instanceof MotionEvent)) { return false; } return mInkWindow.getDecorView().dispatchTouchEvent((MotionEvent) event); onStylusHandwritingMotionEvent((MotionEvent) event); return true; }); } /** * {@inheritDoc} * @hide Loading Loading @@ -2357,7 +2370,8 @@ public class InputMethodService extends AbstractInputMethodService { * * If the IME supports handwriting for the current input, it should return {@code true}, * ensure its inking views are attached to the {@link #getStylusHandwritingWindow()}, and handle * stylus input received on the ink window via {@link #getCurrentInputConnection()}. * stylus input received from {@link #onStylusHandwritingMotionEvent(MotionEvent)} on the * {@link #getStylusHandwritingWindow()} via {@link #getCurrentInputConnection()}. * @return {@code true} if IME can honor the request, {@code false} if IME cannot at this time. */ public boolean onStartStylusHandwriting() { Loading @@ -2365,6 +2379,33 @@ public class InputMethodService extends AbstractInputMethodService { return false; } /** * Called after {@link #onStartStylusHandwriting()} returns {@code true} for every Stylus * {@link MotionEvent}. * By default, this method forwards all {@link MotionEvent}s to the * {@link #getStylusHandwritingWindow()} once its visible, however IME can override it to * receive them sooner. * @param motionEvent {@link MotionEvent} from stylus. */ public void onStylusHandwritingMotionEvent(@NonNull MotionEvent motionEvent) { if (mInkWindow.isInkViewVisible()) { mInkWindow.getDecorView().dispatchTouchEvent(motionEvent); } else { if (mPendingEvents == null) { mPendingEvents = new RingBuffer(MotionEvent.class, MAX_EVENTS_BUFFER); } mPendingEvents.append(motionEvent); mInkWindow.setInkViewVisibilityListener(() -> { if (mPendingEvents != null && !mPendingEvents.isEmpty()) { for (MotionEvent event : mPendingEvents.toArray()) { mInkWindow.getDecorView().dispatchTouchEvent(event); } mPendingEvents.clear(); } }); } } /** * Called when the current stylus handwriting session was finished (either by the system or * via {@link #finishStylusHandwriting()}. Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -18820,6 +18820,7 @@ package android.inputmethodservice { method public void onStartInput(android.view.inputmethod.EditorInfo, boolean); method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean); method public boolean onStartStylusHandwriting(); method public void onStylusHandwritingMotionEvent(@NonNull android.view.MotionEvent); method public void onUnbindInput(); method @Deprecated public void onUpdateCursor(android.graphics.Rect); method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
core/java/android/inputmethodservice/InkWindow.java +78 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.content.Context; import android.os.IBinder; import android.util.Slog; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; import com.android.internal.policy.PhoneWindow; Loading @@ -40,6 +42,9 @@ final class InkWindow extends PhoneWindow { private final WindowManager mWindowManager; private boolean mIsViewAdded; private View mInkView; private InkVisibilityListener mInkViewVisibilityListener; private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener; public InkWindow(@NonNull Context context) { super(context); Loading Loading @@ -102,4 +107,77 @@ final class InkWindow extends PhoneWindow { lp.token = token; setAttributes(lp); } @Override public void addContentView(View view, ViewGroup.LayoutParams params) { if (mInkView == null) { mInkView = view; } else if (mInkView != view) { throw new IllegalStateException("Only one Child Inking view is permitted."); } super.addContentView(view, params); initInkViewVisibilityListener(); } @Override public void setContentView(View view, ViewGroup.LayoutParams params) { mInkView = view; super.setContentView(view, params); initInkViewVisibilityListener(); } @Override public void setContentView(View view) { mInkView = view; super.setContentView(view); initInkViewVisibilityListener(); } @Override public void clearContentView() { if (mGlobalLayoutListener != null && mInkView != null) { mInkView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener); } mGlobalLayoutListener = null; mInkView = null; super.clearContentView(); } /** * Listener used by InkWindow to time the dispatching of {@link MotionEvent}s to Ink view, once * it is visible to user. */ interface InkVisibilityListener { void onInkViewVisible(); } void setInkViewVisibilityListener(InkVisibilityListener listener) { mInkViewVisibilityListener = listener; initInkViewVisibilityListener(); } void initInkViewVisibilityListener() { if (mInkView == null || mInkViewVisibilityListener == null || mGlobalLayoutListener != null) { return; } mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (mInkView.isVisibleToUser()) { if (mInkViewVisibilityListener != null) { mInkViewVisibilityListener.onInkViewVisible(); } mInkView.getViewTreeObserver().removeOnGlobalLayoutListener(this); mGlobalLayoutListener = null; } } }; mInkView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener); } boolean isInkViewVisible() { return getDecorView().getVisibility() == View.VISIBLE && mInkView != null && mInkView.isVisibleToUser(); } }
core/java/android/inputmethodservice/InputMethodService.java +45 −4 Original line number Diff line number Diff line Loading @@ -143,6 +143,7 @@ import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.InputMethodNavButtonFlags; import com.android.internal.inputmethod.InputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; import com.android.internal.util.RingBuffer; import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInputContext; import com.android.internal.view.InlineSuggestionsRequestInfo; Loading Loading @@ -333,6 +334,17 @@ public class InputMethodService extends AbstractInputMethodService { private static final String PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS = "persist.sys.ime.can_render_gestural_nav_buttons"; /** * Number of {@link MotionEvent} to buffer if IME is not ready with Ink view. * This number may be configured eventually based on device's touch sampling frequency. */ private static final int MAX_EVENTS_BUFFER = 500; /** * A circular buffer of size MAX_EVENTS_BUFFER in case IME is taking too long to add ink view. **/ private RingBuffer<MotionEvent> mPendingEvents; /** * Returns whether {@link InputMethodService} is responsible for rendering the back button and * the IME switcher button or not when the gestural navigation is enabled. Loading Loading @@ -954,7 +966,8 @@ public class InputMethodService extends AbstractInputMethodService { mInkWindow.show(); // deliver previous @param stylusEvents stylusEvents.forEach(mInkWindow.getDecorView()::dispatchTouchEvent); stylusEvents.forEach(InputMethodService.this::onStylusHandwritingMotionEvent); // create receiver for channel mHandwritingEventReceiver = new SimpleBatchedInputEventReceiver( channel, Loading @@ -963,11 +976,11 @@ public class InputMethodService extends AbstractInputMethodService { if (!(event instanceof MotionEvent)) { return false; } return mInkWindow.getDecorView().dispatchTouchEvent((MotionEvent) event); onStylusHandwritingMotionEvent((MotionEvent) event); return true; }); } /** * {@inheritDoc} * @hide Loading Loading @@ -2357,7 +2370,8 @@ public class InputMethodService extends AbstractInputMethodService { * * If the IME supports handwriting for the current input, it should return {@code true}, * ensure its inking views are attached to the {@link #getStylusHandwritingWindow()}, and handle * stylus input received on the ink window via {@link #getCurrentInputConnection()}. * stylus input received from {@link #onStylusHandwritingMotionEvent(MotionEvent)} on the * {@link #getStylusHandwritingWindow()} via {@link #getCurrentInputConnection()}. * @return {@code true} if IME can honor the request, {@code false} if IME cannot at this time. */ public boolean onStartStylusHandwriting() { Loading @@ -2365,6 +2379,33 @@ public class InputMethodService extends AbstractInputMethodService { return false; } /** * Called after {@link #onStartStylusHandwriting()} returns {@code true} for every Stylus * {@link MotionEvent}. * By default, this method forwards all {@link MotionEvent}s to the * {@link #getStylusHandwritingWindow()} once its visible, however IME can override it to * receive them sooner. * @param motionEvent {@link MotionEvent} from stylus. */ public void onStylusHandwritingMotionEvent(@NonNull MotionEvent motionEvent) { if (mInkWindow.isInkViewVisible()) { mInkWindow.getDecorView().dispatchTouchEvent(motionEvent); } else { if (mPendingEvents == null) { mPendingEvents = new RingBuffer(MotionEvent.class, MAX_EVENTS_BUFFER); } mPendingEvents.append(motionEvent); mInkWindow.setInkViewVisibilityListener(() -> { if (mPendingEvents != null && !mPendingEvents.isEmpty()) { for (MotionEvent event : mPendingEvents.toArray()) { mInkWindow.getDecorView().dispatchTouchEvent(event); } mPendingEvents.clear(); } }); } } /** * Called when the current stylus handwriting session was finished (either by the system or * via {@link #finishStylusHandwriting()}. Loading