From 27fab2cc2adbb54a318b38faacd37900aa809e1c Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Mon, 16 Dec 2013 17:05:07 +0900 Subject: [PATCH] Refactor touch event forwarding in InputView Bug: 10010128 Change-Id: I82aa4ce847e66cb1241678f39b47b9e27a0f555a --- .../keyboard/KeyboardSwitcher.java | 2 +- .../android/inputmethod/latin/InputView.java | 189 ++++++++++++------ 2 files changed, 134 insertions(+), 57 deletions(-) diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index fb84f1d73..53b448515 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -187,7 +187,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { final MainKeyboardView keyboardView = mKeyboardView; final Keyboard oldKeyboard = keyboardView.getKeyboard(); keyboardView.setKeyboard(keyboard); - mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding); + mCurrentInputView.setKeyboardTopPadding(keyboard.mTopPadding); keyboardView.setKeyPreviewPopupEnabled( Settings.readKeyPreviewPopupEnabled(mPrefs, mResources), Settings.readKeyPreviewPopupDismissDelay(mPrefs, mResources)); diff --git a/java/src/com/android/inputmethod/latin/InputView.java b/java/src/com/android/inputmethod/latin/InputView.java index 81ccf83d8..e711a3f9d 100644 --- a/java/src/com/android/inputmethod/latin/InputView.java +++ b/java/src/com/android/inputmethod/latin/InputView.java @@ -23,87 +23,164 @@ import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; -public final class InputView extends LinearLayout { - private View mSuggestionStripView; - private View mKeyboardView; - private int mKeyboardTopPadding; +import com.android.inputmethod.keyboard.MainKeyboardView; +import com.android.inputmethod.latin.suggestions.SuggestionStripView; - private boolean mIsForwardingEvent; +public final class InputView extends LinearLayout { private final Rect mInputViewRect = new Rect(); - private final Rect mEventForwardingRect = new Rect(); - private final Rect mEventReceivingRect = new Rect(); + private KeyboardTopPaddingForwarder mKeyboardTopPaddingForwarder; public InputView(final Context context, final AttributeSet attrs) { super(context, attrs, 0); } - public void setKeyboardGeometry(final int keyboardTopPadding) { - mKeyboardTopPadding = keyboardTopPadding; - } - @Override protected void onFinishInflate() { - mSuggestionStripView = findViewById(R.id.suggestion_strip_view); - mKeyboardView = findViewById(R.id.keyboard_view); + final SuggestionStripView suggestionStripView = + (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 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; - this.getGlobalVisibleRect(rect); + getGlobalVisibleRect(rect); final int x = (int)me.getX() + rect.left; final int y = (int)me.getY() + rect.top; - final Rect forwardingRect = mEventForwardingRect; - mKeyboardView.getGlobalVisibleRect(forwardingRect); - if (!mIsForwardingEvent && !forwardingRect.contains(x, y)) { - return super.dispatchTouchEvent(me); + // The touch events that hit the top padding of keyboard should be + // forwarded to {@link SuggestionStripView}. + if (mKeyboardTopPaddingForwarder.dispatchTouchEvent(x, y, me)) { + return true; + } + return super.dispatchTouchEvent(me); + } + + /** + * This class forwards series of {@link MotionEvent}s from Forwarder view to + * Receiver view. + * + * @param a {@link View} that may send a {@link MotionEvent} to . + * @param a {@link View} that receives forwarded {@link MotionEvent} from + * . + */ + private static abstract class MotionEventForwarder { + 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; - boolean sendToTarget = false; + // Return true if a touch event of global coordinate x, y needs to be forwarded. + protected abstract boolean needsToForward(final int x, final int y); - switch (me.getAction()) { - case MotionEvent.ACTION_DOWN: - if (y < forwardingLimitY) { - // This down event and further move and up events should be forwarded to the target. - mIsForwardingEvent = true; - sendToTarget = true; + // Translate global x-coordinate to Receiver local coordinate. + protected int translateX(final int x) { + return x - mEventReceivingRect.left; + } + + // Translate global y-coordinate to Receiver local coordinate. + protected int translateY(final int y) { + return y - mEventReceivingRect.top; + } + + // Dispatches a {@link MotioneEvent} to Receiver 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 Sender and + // Receiver are visible. + if (mSenderView.getVisibility() != View.VISIBLE || + mReceiverView.getVisibility() != View.VISIBLE) { + return false; } - break; - case MotionEvent.ACTION_MOVE: - sendToTarget = mIsForwardingEvent; - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - sendToTarget = mIsForwardingEvent; - mIsForwardingEvent = false; - break; + final Rect sendingRect = mEventSendingRect; + mSenderView.getGlobalVisibleRect(sendingRect); + if (!mIsForwardingEvent && !sendingRect.contains(x, y)) { + return false; + } + + boolean shouldForwardToReceiver = false; + + 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 Receiver 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 { + private int mKeyboardTopPadding; + + public KeyboardTopPaddingForwarder(final MainKeyboardView mainKeyboardView, + final SuggestionStripView suggestionStripView) { + super(mainKeyboardView, suggestionStripView); } - if (!sendToTarget) { - return super.dispatchTouchEvent(me); + public void setKeyboardTopPadding(final int keyboardTopPadding) { + mKeyboardTopPadding = keyboardTopPadding; } - final Rect receivingRect = mEventReceivingRect; - mSuggestionStripView.getGlobalVisibleRect(receivingRect); - final int translatedX = x - receivingRect.left; - final int translatedY; - if (y < forwardingLimitY) { - // The forwarded event should have coordinates that are inside of the target. - translatedY = Math.min(y - receivingRect.top, receivingRect.height() - 1); - } else { - translatedY = y - receivingRect.top; + private boolean isInKeyboardTopPadding(final int y) { + return y < mEventSendingRect.top + mKeyboardTopPadding; + } + + @Override + protected boolean needsToForward(final int x, final int y) { + return isInKeyboardTopPadding(y); + } + + @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; } }