Merge "Introduce new IMS method for Stylus events and dispatch" into tm-dev
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
@@ -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,
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
@@ -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()}.
|
||||
|
||||
Reference in New Issue
Block a user