@Override
  public boolean onTouchEvent(@NonNull MotionEvent me) {
    if (getKeyboard() == null) {
      // I mean, if there isn't any keyboard I'm handling, what's the point?
      return false;
    }

    if (areTouchesDisabled(me)) {
      mGestureTypingPathShouldBeDrawn = false;
      return super.onTouchEvent(me);
    }

    final int action = me.getActionMasked();

    PointerTracker pointerTracker = getPointerTracker(me);
    mGestureTypingPathShouldBeDrawn = pointerTracker.isInGestureTyping();
    mGestureDrawingHelper.handleTouchEvent(me);
    // Gesture detector must be enabled only when mini-keyboard is not
    // on the screen.
    if (!mMiniKeyboardPopup.isShowing()
        && !mGestureTypingPathShouldBeDrawn
        && mGestureDetector.onTouchEvent(me)) {
      Logger.d(TAG, "Gesture detected!");
      mKeyPressTimingHandler.cancelAllMessages();
      dismissAllKeyPreviews();
      return true;
    }

    if (action == MotionEvent.ACTION_DOWN) {
      mGestureTypingPathShouldBeDrawn = false;

      mFirstTouchPoint.x = (int) me.getX();
      mFirstTouchPoint.y = (int) me.getY();
      mIsFirstDownEventInsideSpaceBar =
          mSpaceBarKey != null && mSpaceBarKey.isInside(mFirstTouchPoint.x, mFirstTouchPoint.y);
    } else if (action != MotionEvent.ACTION_MOVE) {
      mGestureTypingPathShouldBeDrawn = false;
    }

    // If the motion event is above the keyboard and it's a MOVE event
    // coming even before the first MOVE event into the extension area
    if (!mIsFirstDownEventInsideSpaceBar
        && me.getY() < mExtensionKeyboardYActivationPoint
        && !mMiniKeyboardPopup.isShowing()
        && !mExtensionVisible
        && action == MotionEvent.ACTION_MOVE) {
      if (mExtensionKeyboardAreaEntranceTime <= 0) {
        mExtensionKeyboardAreaEntranceTime = SystemClock.uptimeMillis();
      }

      if (SystemClock.uptimeMillis() - mExtensionKeyboardAreaEntranceTime
          > DELAY_BEFORE_POPPING_UP_EXTENSION_KBD) {
        KeyboardExtension extKbd = ((ExternalAnyKeyboard) getKeyboard()).getExtensionLayout();
        if (extKbd == null || extKbd.getKeyboardResId() == AddOn.INVALID_RES_ID) {
          Logger.i(TAG, "No extension keyboard");
          return super.onTouchEvent(me);
        } else {
          // telling the main keyboard that the last touch was
          // canceled
          MotionEvent cancel =
              MotionEvent.obtain(
                  me.getDownTime(),
                  me.getEventTime(),
                  MotionEvent.ACTION_CANCEL,
                  me.getX(),
                  me.getY(),
                  0);
          super.onTouchEvent(cancel);
          cancel.recycle();

          mExtensionVisible = true;
          dismissAllKeyPreviews();
          if (mExtensionKey == null) {
            mExtensionKey = new AnyKey(new Row(getKeyboard()), getThemedKeyboardDimens());
            mExtensionKey.edgeFlags = 0;
            mExtensionKey.height = 1;
            mExtensionKey.width = 1;
            mExtensionKey.popupResId = extKbd.getKeyboardResId();
            mExtensionKey.externalResourcePopupLayout = mExtensionKey.popupResId != 0;
            mExtensionKey.x = getWidth() / 2;
            mExtensionKey.y = mExtensionKeyboardPopupOffset;
          }
          // so the popup will be right above your finger.
          mExtensionKey.x = ((int) me.getX());

          onLongPress(extKbd, mExtensionKey, mIsStickyExtensionKeyboard, getPointerTracker(me));
          return true;
        }
      } else {
        return super.onTouchEvent(me);
      }
    } else if (mExtensionVisible && me.getY() > mExtensionKeyboardYDismissPoint) {
      // closing the popup
      dismissPopupKeyboard();
      return true;
    } else {
      return super.onTouchEvent(me);
    }
  }
@Test
  public void testKeyClickHappyPath() {
    AnyKeyboard.AnyKey key = findKey('a');
    int primaryCode = key.getCodeAtIndex(0, false);
    Mockito.verifyZeroInteractions(mMockKeyboardListener);

    MotionEvent motionEvent =
        MotionEvent.obtain(
            100,
            100,
            MotionEvent.ACTION_DOWN,
            Keyboard.Key.getCenterX(key),
            Keyboard.Key.getCenterY(key),
            0);
    mViewUnderTest.onTouchEvent(motionEvent);
    motionEvent.recycle();
    Mockito.verify(mMockKeyboardListener).onPress(primaryCode);
    Mockito.verify(mMockKeyboardListener).onFirstDownKey(primaryCode);
    Mockito.verify(mMockKeyboardListener)
        .onGestureTypingInputStart(
            eq(Keyboard.Key.getCenterX(key)),
            eq(Keyboard.Key.getCenterY(key)),
            same(key),
            anyLong());
    Mockito.verifyNoMoreInteractions(mMockKeyboardListener);

    Mockito.reset(mMockKeyboardListener);

    motionEvent =
        MotionEvent.obtain(
            100,
            110,
            MotionEvent.ACTION_UP,
            Keyboard.Key.getCenterX(key),
            Keyboard.Key.getCenterY(key),
            0);
    mViewUnderTest.onTouchEvent(motionEvent);
    motionEvent.recycle();
    InOrder inOrder = Mockito.inOrder(mMockKeyboardListener);
    inOrder
        .verify(mMockKeyboardListener)
        .onKey(eq(primaryCode), same(key), eq(0), any(int[].class), eq(true));
    inOrder.verify(mMockKeyboardListener).onRelease(primaryCode);
    inOrder.verifyNoMoreInteractions();
  }