public void onLongPress(MotionEvent e) {
   mHasPerformedLongPress = childView.performLongClick();
   if (mHasPerformedLongPress) {
     if (rippleHover) {
       startRipple(null);
     }
     cancelPressedEvent();
   }
 }
 private boolean adapterPositionChanged() {
   if (rippleInAdapter) {
     int newPosition = findParentAdapterView().getPositionForView(MaterialRippleLayout.this);
     final boolean changed = newPosition != positionInAdapter;
     positionInAdapter = newPosition;
     if (changed) {
       cancelPressedEvent();
       cancelAnimations();
       childView.setPressed(false);
       setRadius(0);
     }
     return changed;
   }
   return false;
 }
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    boolean superOnTouchEvent = super.onTouchEvent(event);

    if (!isEnabled() || !childView.isEnabled()) return superOnTouchEvent;

    boolean isEventInBounds = bounds.contains((int) event.getX(), (int) event.getY());

    if (isEventInBounds) {
      previousCoords.set(currentCoords.x, currentCoords.y);
      currentCoords.set((int) event.getX(), (int) event.getY());
    }

    boolean gestureResult = gestureDetector.onTouchEvent(event);
    if (gestureResult || mHasPerformedLongPress) {
      return true;
    } else {
      int action = event.getActionMasked();
      switch (action) {
        case MotionEvent.ACTION_UP:
          pendingClickEvent = new PerformClickEvent();

          if (prepressed) {
            childView.setPressed(true);
            postDelayed(
                new Runnable() {
                  @Override
                  public void run() {
                    childView.setPressed(false);
                  }
                },
                ViewConfiguration.getPressedStateDuration());
          }

          if (isEventInBounds) {
            startRipple(pendingClickEvent);
          } else if (!rippleHover) {
            setRadius(0);
          }
          if (!rippleDelayClick && isEventInBounds) {
            pendingClickEvent.run();
          }
          cancelPressedEvent();
          break;
        case MotionEvent.ACTION_DOWN:
          setPositionInAdapter();
          eventCancelled = false;
          pendingPressEvent = new PressedEvent(event);
          if (isInScrollingContainer()) {
            cancelPressedEvent();
            prepressed = true;
            postDelayed(pendingPressEvent, ViewConfiguration.getTapTimeout());
          } else {
            pendingPressEvent.run();
          }
          break;
        case MotionEvent.ACTION_CANCEL:
          if (rippleInAdapter) {
            // dont use current coords in adapter since they tend to jump drastically on scroll
            currentCoords.set(previousCoords.x, previousCoords.y);
            previousCoords = new Point();
          }
          childView.onTouchEvent(event);
          if (rippleHover) {
            if (!prepressed) {
              startRipple(null);
            }
          } else {
            childView.setPressed(false);
          }
          cancelPressedEvent();
          break;
        case MotionEvent.ACTION_MOVE:
          if (rippleHover) {
            if (isEventInBounds && !eventCancelled) {
              invalidate();
            } else if (!isEventInBounds) {
              startRipple(null);
            }
          }

          if (!isEventInBounds) {
            cancelPressedEvent();
            if (hoverAnimator != null) {
              hoverAnimator.cancel();
            }
            childView.onTouchEvent(event);
            eventCancelled = true;
          }
          break;
      }
      return true;
    }
  }