Refactor touch event forwarding in InputView
Bug: 10010128 Change-Id: I82aa4ce847e66cb1241678f39b47b9e27a0f555a
This commit is contained in:
parent
1b5b0a3ebc
commit
27fab2cc2a
2 changed files with 134 additions and 57 deletions
|
@ -187,7 +187,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|
||||||
final MainKeyboardView keyboardView = mKeyboardView;
|
final MainKeyboardView keyboardView = mKeyboardView;
|
||||||
final Keyboard oldKeyboard = keyboardView.getKeyboard();
|
final Keyboard oldKeyboard = keyboardView.getKeyboard();
|
||||||
keyboardView.setKeyboard(keyboard);
|
keyboardView.setKeyboard(keyboard);
|
||||||
mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding);
|
mCurrentInputView.setKeyboardTopPadding(keyboard.mTopPadding);
|
||||||
keyboardView.setKeyPreviewPopupEnabled(
|
keyboardView.setKeyPreviewPopupEnabled(
|
||||||
Settings.readKeyPreviewPopupEnabled(mPrefs, mResources),
|
Settings.readKeyPreviewPopupEnabled(mPrefs, mResources),
|
||||||
Settings.readKeyPreviewPopupDismissDelay(mPrefs, mResources));
|
Settings.readKeyPreviewPopupDismissDelay(mPrefs, mResources));
|
||||||
|
|
|
@ -23,87 +23,164 @@ import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
public final class InputView extends LinearLayout {
|
import com.android.inputmethod.keyboard.MainKeyboardView;
|
||||||
private View mSuggestionStripView;
|
import com.android.inputmethod.latin.suggestions.SuggestionStripView;
|
||||||
private View mKeyboardView;
|
|
||||||
private int mKeyboardTopPadding;
|
|
||||||
|
|
||||||
private boolean mIsForwardingEvent;
|
public final class InputView extends LinearLayout {
|
||||||
private final Rect mInputViewRect = new Rect();
|
private final Rect mInputViewRect = new Rect();
|
||||||
private final Rect mEventForwardingRect = new Rect();
|
private KeyboardTopPaddingForwarder mKeyboardTopPaddingForwarder;
|
||||||
private final Rect mEventReceivingRect = new Rect();
|
|
||||||
|
|
||||||
public InputView(final Context context, final AttributeSet attrs) {
|
public InputView(final Context context, final AttributeSet attrs) {
|
||||||
super(context, attrs, 0);
|
super(context, attrs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKeyboardGeometry(final int keyboardTopPadding) {
|
|
||||||
mKeyboardTopPadding = keyboardTopPadding;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
mSuggestionStripView = findViewById(R.id.suggestion_strip_view);
|
final SuggestionStripView suggestionStripView =
|
||||||
mKeyboardView = findViewById(R.id.keyboard_view);
|
(SuggestionStripView)findViewById(R.id.suggestion_strip_view);
|
||||||
|
final MainKeyboardView mainKeyboardView =
|
||||||
|
(MainKeyboardView)findViewById(R.id.keyboard_view);
|
||||||
|
mKeyboardTopPaddingForwarder = new KeyboardTopPaddingForwarder(
|
||||||
|
mainKeyboardView, suggestionStripView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyboardTopPadding(final int keyboardTopPadding) {
|
||||||
|
mKeyboardTopPaddingForwarder.setKeyboardTopPadding(keyboardTopPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dispatchTouchEvent(final MotionEvent me) {
|
public boolean dispatchTouchEvent(final MotionEvent me) {
|
||||||
if (mSuggestionStripView.getVisibility() != VISIBLE
|
|
||||||
|| mKeyboardView.getVisibility() != VISIBLE) {
|
|
||||||
return super.dispatchTouchEvent(me);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The touch events that hit the top padding of keyboard should be forwarded to
|
|
||||||
// {@link SuggestionStripView}.
|
|
||||||
final Rect rect = mInputViewRect;
|
final Rect rect = mInputViewRect;
|
||||||
this.getGlobalVisibleRect(rect);
|
getGlobalVisibleRect(rect);
|
||||||
final int x = (int)me.getX() + rect.left;
|
final int x = (int)me.getX() + rect.left;
|
||||||
final int y = (int)me.getY() + rect.top;
|
final int y = (int)me.getY() + rect.top;
|
||||||
|
|
||||||
final Rect forwardingRect = mEventForwardingRect;
|
// The touch events that hit the top padding of keyboard should be
|
||||||
mKeyboardView.getGlobalVisibleRect(forwardingRect);
|
// forwarded to {@link SuggestionStripView}.
|
||||||
if (!mIsForwardingEvent && !forwardingRect.contains(x, y)) {
|
if (mKeyboardTopPaddingForwarder.dispatchTouchEvent(x, y, me)) {
|
||||||
return super.dispatchTouchEvent(me);
|
return true;
|
||||||
|
}
|
||||||
|
return super.dispatchTouchEvent(me);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class forwards series of {@link MotionEvent}s from <code>Forwarder</code> view to
|
||||||
|
* <code>Receiver</code> view.
|
||||||
|
*
|
||||||
|
* @param <Sender> a {@link View} that may send a {@link MotionEvent} to <Receiver>.
|
||||||
|
* @param <Receiver> a {@link View} that receives forwarded {@link MotionEvent} from
|
||||||
|
* <Forwarder>.
|
||||||
|
*/
|
||||||
|
private static abstract class MotionEventForwarder<Sender extends View, Receiver extends View> {
|
||||||
|
protected final Sender mSenderView;
|
||||||
|
protected final Receiver mReceiverView;
|
||||||
|
|
||||||
|
private boolean mIsForwardingEvent;
|
||||||
|
protected final Rect mEventSendingRect = new Rect();
|
||||||
|
protected final Rect mEventReceivingRect = new Rect();
|
||||||
|
|
||||||
|
public MotionEventForwarder(final Sender senderView, final Receiver receiverView) {
|
||||||
|
mSenderView = senderView;
|
||||||
|
mReceiverView = receiverView;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int forwardingLimitY = forwardingRect.top + mKeyboardTopPadding;
|
// Return true if a touch event of global coordinate x, y needs to be forwarded.
|
||||||
boolean sendToTarget = false;
|
protected abstract boolean needsToForward(final int x, final int y);
|
||||||
|
|
||||||
switch (me.getAction()) {
|
// Translate global x-coordinate to <code>Receiver</code> local coordinate.
|
||||||
case MotionEvent.ACTION_DOWN:
|
protected int translateX(final int x) {
|
||||||
if (y < forwardingLimitY) {
|
return x - mEventReceivingRect.left;
|
||||||
// This down event and further move and up events should be forwarded to the target.
|
}
|
||||||
mIsForwardingEvent = true;
|
|
||||||
sendToTarget = true;
|
// Translate global y-coordinate to <code>Receiver</code> local coordinate.
|
||||||
|
protected int translateY(final int y) {
|
||||||
|
return y - mEventReceivingRect.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatches a {@link MotioneEvent} to <code>Receiver</code> if needed and returns true.
|
||||||
|
// Otherwise returns false.
|
||||||
|
public boolean dispatchTouchEvent(final int x, final int y, final MotionEvent me) {
|
||||||
|
// Forwards a {link MotionEvent} only if both <code>Sender</code> and
|
||||||
|
// <code>Receiver</code> are visible.
|
||||||
|
if (mSenderView.getVisibility() != View.VISIBLE ||
|
||||||
|
mReceiverView.getVisibility() != View.VISIBLE) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
final Rect sendingRect = mEventSendingRect;
|
||||||
case MotionEvent.ACTION_MOVE:
|
mSenderView.getGlobalVisibleRect(sendingRect);
|
||||||
sendToTarget = mIsForwardingEvent;
|
if (!mIsForwardingEvent && !sendingRect.contains(x, y)) {
|
||||||
break;
|
return false;
|
||||||
case MotionEvent.ACTION_UP:
|
}
|
||||||
case MotionEvent.ACTION_CANCEL:
|
|
||||||
sendToTarget = mIsForwardingEvent;
|
boolean shouldForwardToReceiver = false;
|
||||||
mIsForwardingEvent = false;
|
|
||||||
break;
|
switch (me.getActionMasked()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
// If the down event happens in the forwarding area, successive {@link MotionEvent}s
|
||||||
|
// should be forwarded.
|
||||||
|
if (needsToForward(x, y)) {
|
||||||
|
mIsForwardingEvent = true;
|
||||||
|
shouldForwardToReceiver = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
shouldForwardToReceiver = mIsForwardingEvent;
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
shouldForwardToReceiver = mIsForwardingEvent;
|
||||||
|
mIsForwardingEvent = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldForwardToReceiver) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Rect receivingRect = mEventReceivingRect;
|
||||||
|
mReceiverView.getGlobalVisibleRect(receivingRect);
|
||||||
|
// Translate global coordinates to <code>Receiver</code> local coordinates.
|
||||||
|
me.setLocation(translateX(x), translateY(y));
|
||||||
|
mReceiverView.dispatchTouchEvent(me);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class forwards {@link MotionEvent}s happened in the top padding of
|
||||||
|
* {@link MainKeyboardView} to {@link SuggestionStripView}.
|
||||||
|
*/
|
||||||
|
private static class KeyboardTopPaddingForwarder
|
||||||
|
extends MotionEventForwarder<MainKeyboardView, SuggestionStripView> {
|
||||||
|
private int mKeyboardTopPadding;
|
||||||
|
|
||||||
|
public KeyboardTopPaddingForwarder(final MainKeyboardView mainKeyboardView,
|
||||||
|
final SuggestionStripView suggestionStripView) {
|
||||||
|
super(mainKeyboardView, suggestionStripView);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sendToTarget) {
|
public void setKeyboardTopPadding(final int keyboardTopPadding) {
|
||||||
return super.dispatchTouchEvent(me);
|
mKeyboardTopPadding = keyboardTopPadding;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Rect receivingRect = mEventReceivingRect;
|
private boolean isInKeyboardTopPadding(final int y) {
|
||||||
mSuggestionStripView.getGlobalVisibleRect(receivingRect);
|
return y < mEventSendingRect.top + mKeyboardTopPadding;
|
||||||
final int translatedX = x - receivingRect.left;
|
}
|
||||||
final int translatedY;
|
|
||||||
if (y < forwardingLimitY) {
|
@Override
|
||||||
// The forwarded event should have coordinates that are inside of the target.
|
protected boolean needsToForward(final int x, final int y) {
|
||||||
translatedY = Math.min(y - receivingRect.top, receivingRect.height() - 1);
|
return isInKeyboardTopPadding(y);
|
||||||
} else {
|
}
|
||||||
translatedY = y - receivingRect.top;
|
|
||||||
|
@Override
|
||||||
|
protected int translateY(final int y) {
|
||||||
|
final int translatedY = super.translateY(y);
|
||||||
|
if (isInKeyboardTopPadding(y)) {
|
||||||
|
// The forwarded event should have coordinates that are inside of
|
||||||
|
// the target.
|
||||||
|
return Math.min(translatedY, mEventReceivingRect.height() - 1);
|
||||||
|
}
|
||||||
|
return translatedY;
|
||||||
}
|
}
|
||||||
me.setLocation(translatedX, translatedY);
|
|
||||||
mSuggestionStripView.dispatchTouchEvent(me);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue