Example usage for android.view MotionEvent ACTION_POINTER_DOWN

List of usage examples for android.view MotionEvent ACTION_POINTER_DOWN

Introduction

In this page you can find the example usage for android.view MotionEvent ACTION_POINTER_DOWN.

Prototype

int ACTION_POINTER_DOWN

To view the source code for android.view MotionEvent ACTION_POINTER_DOWN.

Click Source Link

Document

Constant for #getActionMasked : A non-primary pointer has gone down.

Usage

From source file:com.appunite.list.AbsListView.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (!isEnabled()) {
        // A disabled view that is clickable still consumes the touch
        // events, it just doesn't respond to them.
        return isClickable() || isLongClickable();
    }//from ww  w .  j av a 2s  .c o m

    if (mPositionScroller != null) {
        mPositionScroller.stop();
    }

    if (!mIsAttached) {
        // Something isn't right.
        // Since we rely on being attached to get data set change notifications,
        // don't risk doing anything where we might try to resync and find things
        // in a bogus state.
        return false;
    }

    if (mFastScroller != null) {
        boolean intercepted = mFastScroller.onTouchEvent(ev);
        if (intercepted) {
            return true;
        }
    }

    final int action = ev.getAction();

    View v;

    initVelocityTrackerIfNotExists();
    mVelocityTracker.addMovement(ev);

    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN: {
        switch (mTouchMode) {
        case TOUCH_MODE_OVERFLING: {
            mFlingRunnable.endFling();
            if (mPositionScroller != null) {
                mPositionScroller.stop();
            }
            mTouchMode = TOUCH_MODE_OVERSCROLL;
            mMotionX = (int) ev.getX();
            mMotionY = mLastY = (int) ev.getY();
            mMotionCorrection = 0;
            mActivePointerId = ev.getPointerId(0);
            mDirection = 0;
            break;
        }

        default: {
            mActivePointerId = ev.getPointerId(0);
            final int x = (int) ev.getX();
            final int y = (int) ev.getY();
            int motionPosition = pointToPosition(x, y);
            if (!mDataChanged) {
                if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
                        && (getAdapter().isEnabled(motionPosition))) {
                    // User clicked on an actual view (and was not stopping a fling).
                    // It might be a click or a scroll. Assume it is a click until
                    // proven otherwise
                    mTouchMode = TOUCH_MODE_DOWN;
                    // FIXME Debounce
                    if (mPendingCheckForTap == null) {
                        mPendingCheckForTap = new CheckForTap();
                    }
                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                } else {
                    if (mTouchMode == TOUCH_MODE_FLING) {
                        // Stopped a fling. It is a scroll.
                        createScrollingCache();
                        mTouchMode = TOUCH_MODE_SCROLL;
                        mMotionCorrection = 0;
                        motionPosition = findMotionRow(y);
                        mFlingRunnable.flywheelTouch();
                    }
                }
            }

            if (motionPosition >= 0) {
                // Remember where the motion event started
                v = getChildAt(motionPosition - mFirstPosition);
                mMotionViewOriginalTop = v.getTop();
            }
            mMotionX = x;
            mMotionY = y;
            mMotionPosition = motionPosition;
            mLastY = Integer.MIN_VALUE;
            break;
        }
        }

        if (performButtonActionOnTouchDownUnhide(ev)) {
            if (mTouchMode == TOUCH_MODE_DOWN) {
                removeCallbacks(mPendingCheckForTap);
            }
        }
        break;
    }

    case MotionEvent.ACTION_MOVE: {
        int pointerIndex = ev.findPointerIndex(mActivePointerId);
        if (pointerIndex == -1) {
            pointerIndex = 0;
            mActivePointerId = ev.getPointerId(pointerIndex);
        }
        final int y = (int) ev.getY(pointerIndex);

        if (mDataChanged) {
            // Re-sync everything if data has been changed
            // since the scroll operation can query the adapter.
            layoutChildren();
        }

        switch (mTouchMode) {
        case TOUCH_MODE_DOWN:
        case TOUCH_MODE_TAP:
        case TOUCH_MODE_DONE_WAITING:
            // Check if we have moved far enough that it looks more like a
            // scroll than a tap
            startScrollIfNeeded(y);
            break;
        case TOUCH_MODE_SCROLL:
        case TOUCH_MODE_OVERSCROLL:
            scrollIfNeeded(y);
            break;
        }
        break;
    }

    case MotionEvent.ACTION_UP: {
        switch (mTouchMode) {
        case TOUCH_MODE_DOWN:
        case TOUCH_MODE_TAP:
        case TOUCH_MODE_DONE_WAITING:
            final int motionPosition = mMotionPosition;
            final View child = getChildAt(motionPosition - mFirstPosition);

            final float x = ev.getX();
            final boolean inList = x > mListPadding.left && x < getWidth() - mListPadding.right;

            if (child != null && !child.hasFocusable() && inList) {
                if (mTouchMode != TOUCH_MODE_DOWN) {
                    child.setPressed(false);
                }

                if (mPerformClick == null) {
                    mPerformClick = new PerformClick();
                }

                final AbsListView.PerformClick performClick = mPerformClick;
                performClick.mClickMotionPosition = motionPosition;
                performClick.rememberWindowAttachCount();

                mResurrectToPosition = motionPosition;

                if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP) {
                    final Handler handler = getHandler();
                    if (handler != null) {
                        handler.removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ? mPendingCheckForTap
                                : mPendingCheckForLongPress);
                    }
                    mLayoutMode = LAYOUT_NORMAL;
                    if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
                        mTouchMode = TOUCH_MODE_TAP;
                        setSelectedPositionInt(mMotionPosition);
                        layoutChildren();
                        child.setPressed(true);
                        positionSelector(mMotionPosition, child);
                        setPressed(true);
                        if (mSelector != null) {
                            Drawable d = mSelector.getCurrent();
                            if (d != null && d instanceof TransitionDrawable) {
                                ((TransitionDrawable) d).resetTransition();
                            }
                        }
                        if (mTouchModeReset != null) {
                            removeCallbacks(mTouchModeReset);
                        }
                        mTouchModeReset = new Runnable() {
                            @Override
                            public void run() {
                                mTouchModeReset = null;
                                mTouchMode = TOUCH_MODE_REST;
                                child.setPressed(false);
                                setPressed(false);
                                if (!mDataChanged) {
                                    performClick.run();
                                }
                            }
                        };
                        postDelayed(mTouchModeReset, ViewConfiguration.getPressedStateDuration());
                    } else {
                        mTouchMode = TOUCH_MODE_REST;
                        updateSelectorState();
                    }
                    return true;
                } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
                    performClick.run();
                }
            }
            mTouchMode = TOUCH_MODE_REST;
            updateSelectorState();
            break;
        case TOUCH_MODE_SCROLL:
            final int childCount = getChildCount();
            if (childCount > 0) {
                final int firstChildTop = getChildAt(0).getTop();
                final int lastChildBottom = getChildAt(childCount - 1).getBottom();
                final int contentTop = mListPadding.top;
                final int contentBottom = getHeight() - mListPadding.bottom;
                if (mFirstPosition == 0 && firstChildTop >= contentTop
                        && mFirstPosition + childCount < mItemCount
                        && lastChildBottom <= getHeight() - contentBottom) {
                    mTouchMode = TOUCH_MODE_REST;
                    reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                } else {
                    final VelocityTracker velocityTracker = mVelocityTracker;
                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);

                    final int initialVelocity = (int) (velocityTracker.getYVelocity(mActivePointerId)
                            * mVelocityScale);
                    // Fling if we have enough velocity and we aren't at a boundary.
                    // Since we can potentially overfling more than we can overscroll, don't
                    // allow the weird behavior where you can scroll to a boundary then
                    // fling further.
                    if (Math.abs(initialVelocity) > mMinimumVelocity
                            && !((mFirstPosition == 0 && firstChildTop == contentTop - mOverscrollDistance)
                                    || (mFirstPosition + childCount == mItemCount
                                            && lastChildBottom == contentBottom + mOverscrollDistance))) {
                        if (mFlingRunnable == null) {
                            mFlingRunnable = new FlingRunnable();
                        }
                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);

                        mFlingRunnable.start(-initialVelocity);
                    } else {
                        mTouchMode = TOUCH_MODE_REST;
                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                        if (mFlingRunnable != null) {
                            mFlingRunnable.endFling();
                        }
                        if (mPositionScroller != null) {
                            mPositionScroller.stop();
                        }
                    }
                }
            } else {
                mTouchMode = TOUCH_MODE_REST;
                reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
            }
            break;

        case TOUCH_MODE_OVERSCROLL:
            if (mFlingRunnable == null) {
                mFlingRunnable = new FlingRunnable();
            }
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            final int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);

            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
            if (Math.abs(initialVelocity) > mMinimumVelocity) {
                mFlingRunnable.startOverfling(-initialVelocity);
            } else {
                mFlingRunnable.startSpringback();
            }

            break;
        }

        setPressed(false);

        if (mEdgeGlowTop != null) {
            mEdgeGlowTop.onRelease();
            mEdgeGlowBottom.onRelease();
        }

        // Need to redraw since we probably aren't drawing the selector anymore
        invalidate();

        final Handler handler = getHandler();
        if (handler != null) {
            handler.removeCallbacks(mPendingCheckForLongPress);
        }

        recycleVelocityTracker();

        mActivePointerId = INVALID_POINTER;

        if (PROFILE_SCROLLING) {
            if (mScrollProfilingStarted) {
                Debug.stopMethodTracing();
                mScrollProfilingStarted = false;
            }
        }

        // FIXME not needed bacaues we could not implement strict span (j.m.)
        //            if (mScrollStrictSpan != null) {
        //                mScrollStrictSpan.finish();
        //                mScrollStrictSpan = null;
        //            }
        break;
    }

    case MotionEvent.ACTION_CANCEL: {
        switch (mTouchMode) {
        case TOUCH_MODE_OVERSCROLL:
            if (mFlingRunnable == null) {
                mFlingRunnable = new FlingRunnable();
            }
            mFlingRunnable.startSpringback();
            break;

        case TOUCH_MODE_OVERFLING:
            // Do nothing - let it play out.
            break;

        default:
            mTouchMode = TOUCH_MODE_REST;
            setPressed(false);
            View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
            if (motionView != null) {
                motionView.setPressed(false);
            }
            clearScrollingCache();

            final Handler handler = getHandler();
            if (handler != null) {
                handler.removeCallbacks(mPendingCheckForLongPress);
            }

            recycleVelocityTracker();
        }

        if (mEdgeGlowTop != null) {
            mEdgeGlowTop.onRelease();
            mEdgeGlowBottom.onRelease();
        }
        mActivePointerId = INVALID_POINTER;
        break;
    }

    case MotionEvent.ACTION_POINTER_UP: {
        onSecondaryPointerUp(ev);
        final int x = mMotionX;
        final int y = mMotionY;
        final int motionPosition = pointToPosition(x, y);
        if (motionPosition >= 0) {
            // Remember where the motion event started
            v = getChildAt(motionPosition - mFirstPosition);
            mMotionViewOriginalTop = v.getTop();
            mMotionPosition = motionPosition;
        }
        mLastY = y;
        break;
    }

    case MotionEvent.ACTION_POINTER_DOWN: {
        // New pointers take over dragging duties
        final int index = MotionEventCompat.getActionIndex(ev);
        final int id = ev.getPointerId(index);
        final int x = (int) ev.getX(index);
        final int y = (int) ev.getY(index);
        mMotionCorrection = 0;
        mActivePointerId = id;
        mMotionX = x;
        mMotionY = y;
        final int motionPosition = pointToPosition(x, y);
        if (motionPosition >= 0) {
            // Remember where the motion event started
            v = getChildAt(motionPosition - mFirstPosition);
            mMotionViewOriginalTop = v.getTop();
            mMotionPosition = motionPosition;
        }
        mLastY = y;
        break;
    }
    }

    return true;
}

From source file:kr.wdream.ui.PhotoViewer.java

private boolean onTouchEvent(MotionEvent ev) {
    if (animationInProgress != 0 || animationStartTime != 0) {
        return false;
    }//www.  ja v  a2  s .c  o  m

    if (currentEditMode == 2) {
        photoFilterView.onTouch(ev);
        return true;
    }

    if (currentEditMode == 1) {
        if (ev.getPointerCount() == 1) {
            if (photoCropView.onTouch(ev)) {
                updateMinMax(scale);
                return true;
            }
        } else {
            photoCropView.onTouch(null);
        }
    }

    if (captionEditText.isPopupShowing() || captionEditText.isKeyboardVisible()) {
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            closeCaptionEnter(true);
        }
        return true;
    }

    if (currentEditMode == 0 && ev.getPointerCount() == 1 && gestureDetector.onTouchEvent(ev)) {
        if (doubleTap) {
            doubleTap = false;
            moving = false;
            zooming = false;
            checkMinMax(false);
            return true;
        }
    }

    if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
            || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
        if (currentEditMode == 1) {
            photoCropView.cancelAnimationRunnable();
        }
        discardTap = false;
        if (!scroller.isFinished()) {
            scroller.abortAnimation();
        }
        if (!draggingDown && !changingPage) {
            if (canZoom && ev.getPointerCount() == 2) {
                pinchStartDistance = (float) Math.hypot(ev.getX(1) - ev.getX(0), ev.getY(1) - ev.getY(0));
                pinchStartScale = scale;
                pinchCenterX = (ev.getX(0) + ev.getX(1)) / 2.0f;
                pinchCenterY = (ev.getY(0) + ev.getY(1)) / 2.0f;
                pinchStartX = translationX;
                pinchStartY = translationY;
                zooming = true;
                moving = false;
                if (velocityTracker != null) {
                    velocityTracker.clear();
                }
            } else if (ev.getPointerCount() == 1) {
                moveStartX = ev.getX();
                dragY = moveStartY = ev.getY();
                draggingDown = false;
                canDragDown = true;
                if (velocityTracker != null) {
                    velocityTracker.clear();
                }
            }
        }
    } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
        if (currentEditMode == 1) {
            photoCropView.cancelAnimationRunnable();
        }
        if (canZoom && ev.getPointerCount() == 2 && !draggingDown && zooming && !changingPage) {
            discardTap = true;
            scale = (float) Math.hypot(ev.getX(1) - ev.getX(0), ev.getY(1) - ev.getY(0)) / pinchStartDistance
                    * pinchStartScale;
            translationX = (pinchCenterX - getContainerViewWidth() / 2)
                    - ((pinchCenterX - getContainerViewWidth() / 2) - pinchStartX) * (scale / pinchStartScale);
            translationY = (pinchCenterY - getContainerViewHeight() / 2)
                    - ((pinchCenterY - getContainerViewHeight() / 2) - pinchStartY) * (scale / pinchStartScale);
            updateMinMax(scale);
            containerView.invalidate();
        } else if (ev.getPointerCount() == 1) {
            if (velocityTracker != null) {
                velocityTracker.addMovement(ev);
            }
            float dx = Math.abs(ev.getX() - moveStartX);
            float dy = Math.abs(ev.getY() - dragY);
            if (dx > AndroidUtilities.dp(3) || dy > AndroidUtilities.dp(3)) {
                discardTap = true;
            }
            if (!(placeProvider instanceof EmptyPhotoViewerProvider) && currentEditMode == 0 && canDragDown
                    && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) {
                draggingDown = true;
                moving = false;
                dragY = ev.getY();
                if (isActionBarVisible && canShowBottom) {
                    toggleActionBar(false, true);
                } else if (pickerView.getVisibility() == View.VISIBLE) {
                    toggleActionBar(false, true);
                    toggleCheckImageView(false);
                }
                return true;
            } else if (draggingDown) {
                translationY = ev.getY() - dragY;
                containerView.invalidate();
            } else if (!invalidCoords && animationStartTime == 0) {
                float moveDx = moveStartX - ev.getX();
                float moveDy = moveStartY - ev.getY();
                if (moving || currentEditMode != 0
                        || scale == 1 && Math.abs(moveDy) + AndroidUtilities.dp(12) < Math.abs(moveDx)
                        || scale != 1) {
                    if (!moving) {
                        moveDx = 0;
                        moveDy = 0;
                        moving = true;
                        canDragDown = false;
                    }

                    moveStartX = ev.getX();
                    moveStartY = ev.getY();
                    updateMinMax(scale);
                    if (translationX < minX && (currentEditMode != 0 || !rightImage.hasImage())
                            || translationX > maxX && (currentEditMode != 0 || !leftImage.hasImage())) {
                        moveDx /= 3.0f;
                    }
                    if (maxY == 0 && minY == 0 && currentEditMode == 0) {
                        if (translationY - moveDy < minY) {
                            translationY = minY;
                            moveDy = 0;
                        } else if (translationY - moveDy > maxY) {
                            translationY = maxY;
                            moveDy = 0;
                        }
                    } else {
                        if (translationY < minY || translationY > maxY) {
                            moveDy /= 3.0f;
                        }
                    }

                    translationX -= moveDx;
                    if (scale != 1 || currentEditMode != 0) {
                        translationY -= moveDy;
                    }

                    containerView.invalidate();
                }
            } else {
                invalidCoords = false;
                moveStartX = ev.getX();
                moveStartY = ev.getY();
            }
        }
    } else if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL
            || ev.getActionMasked() == MotionEvent.ACTION_UP
            || ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
        if (currentEditMode == 1) {
            photoCropView.startAnimationRunnable();
        }
        if (zooming) {
            invalidCoords = true;
            if (scale < 1.0f) {
                updateMinMax(1.0f);
                animateTo(1.0f, 0, 0, true);
            } else if (scale > 3.0f) {
                float atx = (pinchCenterX - getContainerViewWidth() / 2)
                        - ((pinchCenterX - getContainerViewWidth() / 2) - pinchStartX)
                                * (3.0f / pinchStartScale);
                float aty = (pinchCenterY - getContainerViewHeight() / 2)
                        - ((pinchCenterY - getContainerViewHeight() / 2) - pinchStartY)
                                * (3.0f / pinchStartScale);
                updateMinMax(3.0f);
                if (atx < minX) {
                    atx = minX;
                } else if (atx > maxX) {
                    atx = maxX;
                }
                if (aty < minY) {
                    aty = minY;
                } else if (aty > maxY) {
                    aty = maxY;
                }
                animateTo(3.0f, atx, aty, true);
            } else {
                checkMinMax(true);
            }
            zooming = false;
        } else if (draggingDown) {
            if (Math.abs(dragY - ev.getY()) > getContainerViewHeight() / 6.0f) {
                closePhoto(true, false);
            } else {
                if (pickerView.getVisibility() == View.VISIBLE) {
                    toggleActionBar(true, true);
                    toggleCheckImageView(true);
                }
                animateTo(1, 0, 0, false);
            }
            draggingDown = false;
        } else if (moving) {
            float moveToX = translationX;
            float moveToY = translationY;
            updateMinMax(scale);
            moving = false;
            canDragDown = true;
            float velocity = 0;
            if (velocityTracker != null && scale == 1) {
                velocityTracker.computeCurrentVelocity(1000);
                velocity = velocityTracker.getXVelocity();
            }

            if (currentEditMode == 0) {
                if ((translationX < minX - getContainerViewWidth() / 3 || velocity < -AndroidUtilities.dp(650))
                        && rightImage.hasImage()) {
                    goToNext();
                    return true;
                }
                if ((translationX > maxX + getContainerViewWidth() / 3 || velocity > AndroidUtilities.dp(650))
                        && leftImage.hasImage()) {
                    goToPrev();
                    return true;
                }
            }

            if (translationX < minX) {
                moveToX = minX;
            } else if (translationX > maxX) {
                moveToX = maxX;
            }
            if (translationY < minY) {
                moveToY = minY;
            } else if (translationY > maxY) {
                moveToY = maxY;
            }
            animateTo(scale, moveToX, moveToY, false);
        }
    }
    return false;
}

From source file:org.telegram.ui.ArticleViewer.java

private boolean processTouchEvent(MotionEvent ev) {
    if (photoAnimationInProgress != 0 || animationStartTime != 0) {
        return false;
    }//w w w  .  ja v  a  2  s .  co  m

    if (ev.getPointerCount() == 1 && gestureDetector.onTouchEvent(ev) && doubleTap) {
        doubleTap = false;
        moving = false;
        zooming = false;
        checkMinMax(false);
        return true;
    }

    if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
            || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
        discardTap = false;
        if (!scroller.isFinished()) {
            scroller.abortAnimation();
        }
        if (!draggingDown && !changingPage) {
            if (canZoom && ev.getPointerCount() == 2) {
                pinchStartDistance = (float) Math.hypot(ev.getX(1) - ev.getX(0), ev.getY(1) - ev.getY(0));
                pinchStartScale = scale;
                pinchCenterX = (ev.getX(0) + ev.getX(1)) / 2.0f;
                pinchCenterY = (ev.getY(0) + ev.getY(1)) / 2.0f;
                pinchStartX = translationX;
                pinchStartY = translationY;
                zooming = true;
                moving = false;
                if (velocityTracker != null) {
                    velocityTracker.clear();
                }
            } else if (ev.getPointerCount() == 1) {
                moveStartX = ev.getX();
                dragY = moveStartY = ev.getY();
                draggingDown = false;
                canDragDown = true;
                if (velocityTracker != null) {
                    velocityTracker.clear();
                }
            }
        }
    } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
        if (canZoom && ev.getPointerCount() == 2 && !draggingDown && zooming && !changingPage) {
            discardTap = true;
            scale = (float) Math.hypot(ev.getX(1) - ev.getX(0), ev.getY(1) - ev.getY(0)) / pinchStartDistance
                    * pinchStartScale;
            translationX = (pinchCenterX - getContainerViewWidth() / 2)
                    - ((pinchCenterX - getContainerViewWidth() / 2) - pinchStartX) * (scale / pinchStartScale);
            translationY = (pinchCenterY - getContainerViewHeight() / 2)
                    - ((pinchCenterY - getContainerViewHeight() / 2) - pinchStartY) * (scale / pinchStartScale);
            updateMinMax(scale);
            photoContainerView.invalidate();
        } else if (ev.getPointerCount() == 1) {
            if (velocityTracker != null) {
                velocityTracker.addMovement(ev);
            }
            float dx = Math.abs(ev.getX() - moveStartX);
            float dy = Math.abs(ev.getY() - dragY);
            if (dx > AndroidUtilities.dp(3) || dy > AndroidUtilities.dp(3)) {
                discardTap = true;
            }
            if (canDragDown && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) {
                draggingDown = true;
                moving = false;
                dragY = ev.getY();
                if (isActionBarVisible) {
                    toggleActionBar(false, true);
                }
                return true;
            } else if (draggingDown) {
                translationY = ev.getY() - dragY;
                photoContainerView.invalidate();
            } else if (!invalidCoords && animationStartTime == 0) {
                float moveDx = moveStartX - ev.getX();
                float moveDy = moveStartY - ev.getY();
                if (moving || scale == 1 && Math.abs(moveDy) + AndroidUtilities.dp(12) < Math.abs(moveDx)
                        || scale != 1) {
                    if (!moving) {
                        moveDx = 0;
                        moveDy = 0;
                        moving = true;
                        canDragDown = false;
                    }

                    moveStartX = ev.getX();
                    moveStartY = ev.getY();
                    updateMinMax(scale);
                    if (translationX < minX && (!rightImage.hasImage())
                            || translationX > maxX && !leftImage.hasImage()) {
                        moveDx /= 3.0f;
                    }
                    if (maxY == 0 && minY == 0) {
                        if (translationY - moveDy < minY) {
                            translationY = minY;
                            moveDy = 0;
                        } else if (translationY - moveDy > maxY) {
                            translationY = maxY;
                            moveDy = 0;
                        }
                    } else {
                        if (translationY < minY || translationY > maxY) {
                            moveDy /= 3.0f;
                        }
                    }

                    translationX -= moveDx;
                    if (scale != 1) {
                        translationY -= moveDy;
                    }

                    photoContainerView.invalidate();
                }
            } else {
                invalidCoords = false;
                moveStartX = ev.getX();
                moveStartY = ev.getY();
            }
        }
    } else if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL
            || ev.getActionMasked() == MotionEvent.ACTION_UP
            || ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
        if (zooming) {
            invalidCoords = true;
            if (scale < 1.0f) {
                updateMinMax(1.0f);
                animateTo(1.0f, 0, 0, true);
            } else if (scale > 3.0f) {
                float atx = (pinchCenterX - getContainerViewWidth() / 2)
                        - ((pinchCenterX - getContainerViewWidth() / 2) - pinchStartX)
                                * (3.0f / pinchStartScale);
                float aty = (pinchCenterY - getContainerViewHeight() / 2)
                        - ((pinchCenterY - getContainerViewHeight() / 2) - pinchStartY)
                                * (3.0f / pinchStartScale);
                updateMinMax(3.0f);
                if (atx < minX) {
                    atx = minX;
                } else if (atx > maxX) {
                    atx = maxX;
                }
                if (aty < minY) {
                    aty = minY;
                } else if (aty > maxY) {
                    aty = maxY;
                }
                animateTo(3.0f, atx, aty, true);
            } else {
                checkMinMax(true);
            }
            zooming = false;
        } else if (draggingDown) {
            if (Math.abs(dragY - ev.getY()) > getContainerViewHeight() / 6.0f) {
                closePhoto(true);
            } else {
                animateTo(1, 0, 0, false);
            }
            draggingDown = false;
        } else if (moving) {
            float moveToX = translationX;
            float moveToY = translationY;
            updateMinMax(scale);
            moving = false;
            canDragDown = true;
            float velocity = 0;
            if (velocityTracker != null && scale == 1) {
                velocityTracker.computeCurrentVelocity(1000);
                velocity = velocityTracker.getXVelocity();
            }

            if ((translationX < minX - getContainerViewWidth() / 3 || velocity < -AndroidUtilities.dp(650))
                    && rightImage.hasImage()) {
                goToNext();
                return true;
            }
            if ((translationX > maxX + getContainerViewWidth() / 3 || velocity > AndroidUtilities.dp(650))
                    && leftImage.hasImage()) {
                goToPrev();
                return true;
            }

            if (translationX < minX) {
                moveToX = minX;
            } else if (translationX > maxX) {
                moveToX = maxX;
            }
            if (translationY < minY) {
                moveToY = minY;
            } else if (translationY > maxY) {
                moveToY = maxY;
            }
            animateTo(scale, moveToX, moveToY, false);
        }
    }
    return false;
}