Example usage for android.view MotionEvent ACTION_POINTER_UP

List of usage examples for android.view MotionEvent ACTION_POINTER_UP

Introduction

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

Prototype

int ACTION_POINTER_UP

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

Click Source Link

Document

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

Usage

From source file:com.example.manan.enhancedurdureader.EpubReader.BookView.java

@TargetApi(Build.VERSION_CODES.KITKAT)
@Override/*from  w  w w  .  ja  va2  s  .  c o m*/
public void onActivityCreated(Bundle saved) {
    super.onActivityCreated(saved);
    view = (WebView) getView().findViewById(R.id.Viewport);
    view.getSettings().setTextZoom(textSize);

    mScaleDetector = new ScaleGestureDetector(getActivity().getBaseContext(),
            new ScaleGestureDetector.OnScaleGestureListener() {
                @Override
                public void onScaleEnd(ScaleGestureDetector detector) {
                }

                @Override
                public boolean onScaleBegin(ScaleGestureDetector detector) {
                    return true;
                }

                @Override
                public boolean onScale(ScaleGestureDetector detector) {
                    //Log.w(LOG_KEY, "zoom ongoing, scale: " + detector.getScaleFactor());
                    return false;
                }

            });

    // enable JavaScript for cool things to happen!
    view.getSettings().setJavaScriptEnabled(true);

    // ----- SWIPE PAGE
    view.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            /*   if (state == ViewStateEnum.books)
                  swipePage(v, event, 0);
               //int fontSize, newFont;*/
            WebView view = (WebView) v;

            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                x1 = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                if (mode != ZOOM && swipeFlag) {
                    //if (state == ViewStateEnum.books)
                    //swipePage(v, event, 0);

                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                if (oldDist > 10f) {
                    mode = ZOOM;
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                break;

            case MotionEvent.ACTION_MOVE:

                if (mode == ZOOM) {
                    float newDist = spacing(event);
                    if (newDist > 10f) {
                        float scale = newDist / oldDist;
                        if (scale > 1) {
                            int currentTextSize = view.getSettings().getTextZoom();
                            textSize = currentTextSize + 15;
                            view.getSettings().setTextZoom(textSize);

                            mode = NONE;
                            swipeFlag = false;
                        } else {
                            int currentTextSize = view.getSettings().getTextZoom();
                            textSize = currentTextSize - 15;
                            view.getSettings().setTextZoom(textSize);
                            mode = NONE;
                            swipeFlag = false;
                        }
                    }
                }
                break;

            }
            return view.onTouchEvent(event);
        }

    });

    // ----- NOTE & LINK
    view.setOnLongClickListener(new OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            Message msg = new Message();
            msg.setTarget(new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    String url = msg.getData().getString(getString(R.string.url));

                    if (url != null)
                        navigator.setNote(url, index);
                }
            });
            view.requestFocusNodeHref(msg);

            return false;
        }
    });

    view.setWebViewClient(new WebViewClient() {
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            try {
                navigator.setBookPage(url, index);
            } catch (Exception e) {
                errorMessage(getString(R.string.error_LoadPage));
            }
            return true;
        }
    });

    loadPage(viewedPage);
}

From source file:com.fishstix.dosboxfree.ButtonLayout.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);
    final int pointerIndex = MotionEventCompat.getActionIndex(ev);//((action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT);
    final int pId = ev.getPointerId(pointerIndex) + 1;
    KeyEvent evt = null;//from  w w w.  j a va2 s  .  c  om
    Message msg = Message.obtain();
    msg.what = DBMain.HANDLER_SEND_KEYCODE;
    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
    case MotionEvent.ACTION_POINTER_DOWN: {
        Log.i("DosBoxTurbo", "button onDown()");
        int x = (int) ev.getX(pointerIndex);//(int) mWrap.getX(ev,pointerIndex);
        int width = getWidth();
        //int y = (int) mWrap.getY(ev,pointerIndex);
        float val = ((float) x / (float) width) * 4f;
        if (val < 1.0) {
            // first button
            if (virtualbutton_hm.indexOfValue(HardCodeWrapper.KEYCODE_VIRTUAL_A) > 0)
                return false;
            evt = new KeyEvent(action, HardCodeWrapper.KEYCODE_VIRTUAL_A);
            virtualbutton_hm.put(pId, HardCodeWrapper.KEYCODE_VIRTUAL_A);
            msg.arg2 = HardCodeWrapper.KEYCODE_VIRTUAL_A;
            mDBLauncher.bButtonA.setBackgroundColor(0x80FF0000);
        } else if (val < 2.0) {
            if (virtualbutton_hm.indexOfValue(HardCodeWrapper.KEYCODE_VIRTUAL_B) > 0)
                return false;
            evt = new KeyEvent(action, HardCodeWrapper.KEYCODE_VIRTUAL_B);
            virtualbutton_hm.put(pId, HardCodeWrapper.KEYCODE_VIRTUAL_B);
            msg.arg2 = HardCodeWrapper.KEYCODE_VIRTUAL_B;
            mDBLauncher.bButtonB.setBackgroundColor(0x80FF0000);
        } else if (val < 3.0) {
            if (virtualbutton_hm.indexOfValue(HardCodeWrapper.KEYCODE_VIRTUAL_C) > 0)
                return false;
            evt = new KeyEvent(action, HardCodeWrapper.KEYCODE_VIRTUAL_C);
            virtualbutton_hm.put(pId, HardCodeWrapper.KEYCODE_VIRTUAL_C);
            msg.arg2 = HardCodeWrapper.KEYCODE_VIRTUAL_C;
            mDBLauncher.bButtonC.setBackgroundColor(0x80FF0000);
        } else {
            if (virtualbutton_hm.indexOfValue(HardCodeWrapper.KEYCODE_VIRTUAL_D) > 0)
                return false;
            evt = new KeyEvent(action, HardCodeWrapper.KEYCODE_VIRTUAL_D);
            virtualbutton_hm.put(pId, HardCodeWrapper.KEYCODE_VIRTUAL_D);
            msg.arg2 = HardCodeWrapper.KEYCODE_VIRTUAL_D;
            mDBLauncher.bButtonD.setBackgroundColor(0x80FF0000);
        }
        msg.obj = evt;
        msg.arg1 = 0;
        mDBLauncher.mSurfaceView.virtButton[pointerIndex] = true;
        mDBLauncher.mSurfaceView.mFilterLongClick = true; // prevent long click listener from getting in the way
        mDBLauncher.mHandler.sendMessage(msg);
        return true;
    }

    case MotionEvent.ACTION_CANCEL:
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_POINTER_UP: {
        Log.i("DosBoxTurbo", "button onUp()");
        msg.arg2 = virtualbutton_hm.get(pId);
        switch (msg.arg2) {
        case HardCodeWrapper.KEYCODE_VIRTUAL_A:
            mDBLauncher.bButtonA.setBackgroundColor(0x80FFFF00);
            break;
        case HardCodeWrapper.KEYCODE_VIRTUAL_B:
            mDBLauncher.bButtonB.setBackgroundColor(0x80FFFF00);
            break;
        case HardCodeWrapper.KEYCODE_VIRTUAL_C:
            mDBLauncher.bButtonC.setBackgroundColor(0x80FFFF00);
            break;
        case HardCodeWrapper.KEYCODE_VIRTUAL_D:
            mDBLauncher.bButtonD.setBackgroundColor(0x80FFFF00);
            break;
        }
        virtualbutton_hm.delete(pId);
        if (msg.arg2 == 0)
            return false;
        evt = new KeyEvent(action, msg.arg2);
        msg.obj = evt;
        msg.arg1 = 1;
        mDBLauncher.mSurfaceView.virtButton[pointerIndex] = false;
        mDBLauncher.mSurfaceView.mFilterLongClick = false;
        mDBLauncher.mHandler.sendMessage(msg);
        return true;
    }
    }
    return false;
}

From source file:com.bluetech.gallery5.ui.ImageDetailFragment.java

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    /*/*from  w w w  .j a v a  2s  .c  om*/
    // Inflate and locate the main ImageView
    final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
    mImageView = (ImageView) v.findViewById(R.id.imageRecycView);
    return v;
    */
    final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
    mImageView = (ImageView) v.findViewById(R.id.imageRecycView);
    //ImageView img = new ImageView(getActivity());

    mImageView.setPadding(6, 6, 6, 6);

    // mImageView.setLayoutParams(new Gallery.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)) ;
    //ImageViewHelperURL.setUrlDrawable((ImageView) img, url, R.drawable.no_image) ;

    mImageView.setOnTouchListener(new View.OnTouchListener() {
        private static final String TAG = "SlideImageView";
        // These matrices will be used to move and zoom image
        Matrix matrix = new Matrix();
        Matrix savedMatrix = new Matrix();

        // We can be in one of these 3 states
        static final int NONE = 0;
        static final int DRAG = 1;
        static final int ZOOM = 2;
        int mode = NONE;

        // Remember some things for zooming
        PointF start = new PointF();
        PointF mid = new PointF();
        float oldDist = 1f;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            ImageView view = (ImageView) v;

            // Dump touch event to log
            dumpEvent(event);

            // Handle touch events here...
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                savedMatrix.set(matrix);
                start.set(event.getX(), event.getY());
                Log.d(TAG, "mode=DRAG");
                mode = DRAG;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                Log.d(TAG, "oldDist=" + oldDist);
                if (oldDist > 10f) {
                    savedMatrix.set(matrix);
                    midPoint(mid, event);
                    mode = ZOOM;
                    Log.d(TAG, "mode=ZOOM");
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                Log.d(TAG, "mode=NONE");
                break;
            case MotionEvent.ACTION_MOVE:
                if (mode == DRAG) {
                    // ...
                    matrix.set(savedMatrix);
                    matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
                } else if (mode == ZOOM) {
                    float newDist = spacing(event);
                    Log.d(TAG, "newDist=" + newDist);
                    if (newDist > 10f) {
                        matrix.set(savedMatrix);
                        float scale = newDist / oldDist;
                        Log.d(TAG, "ZOOOOOOOM: " + scale);
                        matrix.postScale(scale, scale, mid.x, mid.y);
                    }
                }
                break;
            }

            view.setImageMatrix(matrix);
            return true; // indicate event was handled
        }

        /** Show an event in the LogCat view, for debugging */
        private void dumpEvent(MotionEvent event) {
            String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?",
                    "8?", "9?" };
            StringBuilder sb = new StringBuilder();
            int action = event.getAction();
            int actionCode = action & MotionEvent.ACTION_MASK;
            sb.append("event ACTION_").append(names[actionCode]);
            if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) {
                sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
                sb.append(")");
            }
            sb.append("[");
            for (int i = 0; i < event.getPointerCount(); i++) {
                sb.append("#").append(i);
                sb.append("(pid ").append(event.getPointerId(i));
                sb.append(")=").append((int) event.getX(i));
                sb.append(",").append((int) event.getY(i));
                if (i + 1 < event.getPointerCount())
                    sb.append(";");
            }
            sb.append("]");
            Log.d(TAG, sb.toString());
        }

        /** Determine the space between the first two fingers */
        private float spacing(MotionEvent event) {
            float x = event.getX(0) - event.getX(1);
            float y = event.getY(0) - event.getY(1);
            return (float) Math.sqrt(x * x + y * y);
        }

        /** Calculate the mid point of the first two fingers */
        private void midPoint(PointF point, MotionEvent event) {
            float x = event.getX(0) + event.getX(1);
            float y = event.getY(0) + event.getY(1);
            point.set(x / 2, y / 2);
        }
    });

    return v;

}

From source file:com.idrv.coach.ui.view.LoopViewPager.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (MotionEventCompat.getActionMasked(ev)) {
    case MotionEvent.ACTION_DOWN:
    case MotionEvent.ACTION_MOVE:
    case MotionEventCompat.ACTION_POINTER_DOWN:
        mHandler.removeMessages(AUTO_SCROLL_MESSAGE);
        break;/*from   w  w  w.j  a  v  a  2 s .c o  m*/
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_POINTER_UP:
    case MotionEvent.ACTION_POINTER_2_UP:
    case MotionEvent.ACTION_POINTER_3_UP:
    case MotionEvent.ACTION_CANCEL:
        mHandler.removeMessages(AUTO_SCROLL_MESSAGE);
        mHandler.sendEmptyMessageDelayed(AUTO_SCROLL_MESSAGE, delayTimeInMills);
        break;
    default:
        break;
    }
    return super.onTouchEvent(ev);
}

From source file:me.wizos.loread.view.webview.NestedScrollWebView.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    final int actionMasked = ev.getActionMasked();

    switch (actionMasked) {
    case MotionEvent.ACTION_DOWN:
        mIsBeingDragged = false;//  w w  w  .ja va  2  s.  c  om

        // Remember where the motion event started
        mLastMotionY = (int) ev.getY();
        //                downY = (int) ev.getY();

        mActivePointerId = ev.getPointerId(0);
        startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
        break;

    case MotionEvent.ACTION_MOVE:
        //                KLog.e("");
        final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
        if (activePointerIndex == -1) {
            break;
        }
        //                if( !onlyVerticalMove(ev) ){
        //                    break;
        //                }

        final int y = (int) ev.getY(activePointerIndex);
        int deltaY = mLastMotionY - y;
        if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
            deltaY -= mScrollConsumed[1];
        }
        // Scroll to follow the motion event
        mLastMotionY = y - mScrollOffset[1];

        final int oldY = getScrollY();
        final int scrolledDeltaY = Math.max(0, oldY + deltaY) - oldY;
        final int unconsumedY = deltaY - scrolledDeltaY;
        if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset)) {
            mLastMotionY -= mScrollOffset[1];
        }
        //                KLog.e("?");
        break;
    case MotionEvent.ACTION_UP:
        mActivePointerId = INVALID_POINTER;
        endDrag();
        break;
    case MotionEvent.ACTION_CANCEL:
        mActivePointerId = INVALID_POINTER;
        endDrag();
        break;
    case MotionEvent.ACTION_POINTER_DOWN: {
        final int index = ev.getActionIndex();
        mLastMotionY = (int) ev.getY(index);
        mActivePointerId = ev.getPointerId(index);
        break;
    }
    case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
        break;
    default:
        break;
    }
    return super.onTouchEvent(ev);
}

From source file:danonino.danonino_the_game.Core.GamePanel.java

@Override
public boolean onTouchEvent(MotionEvent event) {
    int action = MotionEventCompat.getActionMasked(event);

    switch (action) {
    case MotionEvent.ACTION_POINTER_DOWN:
    case MotionEvent.ACTION_DOWN: {
        if (this.gameOver) {
            GameOver.onTouch(event);/* ww  w .j av  a 2  s. com*/
        } else if (this.powerUpLabel != null && this.powerUpLabel.onTouch(event) == 1) {
            return true;
        }
        if (!this.joystickEnabled && action == MotionEvent.ACTION_DOWN) {
            this.movePlayer(event);
        }
        return true;
    }
    case MotionEvent.ACTION_MOVE: {
        this.movePlayer(event);
        break;
    }
    case MotionEvent.ACTION_POINTER_UP:
    case MotionEvent.ACTION_UP: {
        if (this.gameOver) {
            if (GameOver.onTouch(event) == 1) {
                this.initPlayerFeatures();
                Player.setPowerUp(null);
                this.powerUpLabel = null;
            } else if (GameOver.onTouch(event) == 2) {
                Intent i = new Intent(getContext(), MoreGamesMenu.class);
                getContext().startActivity(i);
            }
        } else if (this.powerUpLabel != null) {
            if (this.powerUpLabel.onTouch(event) == 1) {
                Player.getPowerUp().applyEffect(this.player);
            }
        }
        this.player.setSpeedX(0);
        this.player.setSpeedY(0);
        joystick.resetPosition();
        return true;
    }
    }
    return super.onTouchEvent(event);
}

From source file:com.tearoffcalendar.activities.FaceDownCardFragment.java

public boolean onTouch(View view, MotionEvent event) {
    // We need to register click here
    final float y = event.getRawY();
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        deltaY = 0;/*from  w w  w .  j a  v a  2s. co  m*/
        clickStartedOnY = y;
        Log.v(TAG, "Click started on:" + String.valueOf(clickStartedOnY));
        break;
    case MotionEvent.ACTION_UP:
        Log.v(TAG, "Resulted deltaY:" + String.valueOf(deltaY));
        // This one is for when finger is up, not a rude gesture bro!
        if (deltaY >= DELTA_Y_MAX) {
            Log.v(TAG, "Greater than max of delta y - not a click!");
        } else {
            Log.v(TAG, "Smaller than max of delta y - a click!");
            if (null != onFaceDownCardClickListener) {
                Log.v(TAG, "Calling on face down card click listener");
                onFaceDownCardClickListener.onFaceDownCardClick();
            } else {
                Log.e(TAG, "On face down card click listener is missing!");
            }
        }
        deltaY = clickStartedOnY = 0;
        break;
    case MotionEvent.ACTION_POINTER_DOWN:
        break;
    case MotionEvent.ACTION_POINTER_UP:
        break;
    case MotionEvent.ACTION_MOVE:
        deltaY += Math.abs(y - clickStartedOnY);
        Log.v(TAG, "Current delta: " + String.valueOf(deltaY));
        break;
    }
    return false;
}

From source file:com.telenav.expandablepager.SlidingContainer.java

private boolean translate(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);
    int stepSize = stopValues.size();

    switch (action) {
    case MotionEvent.ACTION_DOWN: {
        startYCoordinate = ev.getRawY();
        translated = 0;//from w w w.ja va  2  s  .c  om
        break;
    }
    case MotionEvent.ACTION_MOVE: {
        touchDelta = (startYCoordinate - ev.getRawY());
        if (Math.abs(touchDelta) > slideThreshold) {
            float startingPointY, nextPointY, maxDiff, tempDelta, auxDelta = 0;
            tempDelta = touchDelta + (touchDelta < 0 ? 1 : -1) * slideThreshold;
            startingPointY = stopValues.get(stopValueIndex);
            if (!isUpwardGesture() && stopValueIndex >= 1) {
                nextPointY = stopValues.get(stopValueIndex - 1);
                maxDiff = nextPointY - stopValues.get(stopValueIndex);
                auxDelta = Math.min(-tempDelta, maxDiff);
            } else if (isUpwardGesture() && stopValueIndex < stepSize - 1) {
                nextPointY = stopValues.get(stopValueIndex + 1);
                maxDiff = nextPointY - stopValues.get(stopValueIndex);
                auxDelta = Math.max(-tempDelta, maxDiff);
            }
            float preTranslated = translated;
            translated = startingPointY + auxDelta;
            setTranslationY(translated);
            if (preTranslated != translated)
                notifySlideEvent(translated);
            return false;
        }
        return true;
    }
    case MotionEvent.ACTION_UP: {
        if (Math.abs(touchDelta) > slideThreshold) {
            if (!isUpwardGesture() && stopValueIndex > 0)
                stopValueIndex--;
            else if (isUpwardGesture() && stopValueIndex < stepSize - 1)
                stopValueIndex++;
            if (!stopValues.contains(translated)) {
                animate(stopValues.get(stopValueIndex));
            } else
                onSettled(stopValueIndex);
            startYCoordinate = -1;
            touchDelta = 0;
        }
        break;
    }
    case MotionEvent.ACTION_CANCEL: {
        break;
    }
    case MotionEvent.ACTION_POINTER_UP: {
        break;
    }
    }
    return true;
}

From source file:org.libreoffice.impressremote.fragment.slides.PointerFragment.java

@Override
public boolean onTouch(View v, MotionEvent event) {

    float x = (event.getX() - xoffset) / displaywidth;
    float y = (event.getY() - yoffset) / displayheight;

    // get masked action
    int aMaskedAction = event.getActionMasked();

    switch (aMaskedAction) {
    case MotionEvent.ACTION_DOWN:
    case MotionEvent.ACTION_POINTER_DOWN:
        // a pointer start
        mCommunicationService.getCommandsTransmitter().startPointer(x, y);
        break;//  w w  w  . jav  a  2  s. co m
    case MotionEvent.ACTION_MOVE:
        // a pointer was moved
        if (nextUpdate <= event.getEventTime()) {
            mCommunicationService.getCommandsTransmitter().movePointer(x, y);
            nextUpdate = event.getEventTime() + REFRESH_MILLIS;
        }
        break;
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_POINTER_UP:
    case MotionEvent.ACTION_CANCEL:
        // a pointer was removed
        mCommunicationService.getCommandsTransmitter().stopPointer();
        break;
    }
    return true;
}

From source file:com.arthurpitman.common.SlidingPanel.java

@Override
public boolean onTouchEvent(MotionEvent event) {
    float y = event.getY();
    int action = event.getActionMasked();
    int pointerId = event.getPointerId(event.getActionIndex());

    switch (action) {
    case MotionEvent.ACTION_POINTER_DOWN:
    case MotionEvent.ACTION_DOWN:
        startTouchY = y;//from  w  ww. jav  a2  s .  co m
        startTouchScrollY = getScrollY();

        // if touch didn't occur on the actual control, ignore it
        float touchBoundary = viewHeight - collapsedHeight - startTouchScrollY;
        if (y < touchBoundary) {
            return false;
        }

        // start tracking velocity
        if (velocityTracker == null) {
            velocityTracker = VelocityTracker.obtain();
        } else {
            velocityTracker.clear();
        }
        velocityTracker.addMovement(event);
        break;

    case MotionEvent.ACTION_MOVE:
        // determine if a valid touch has started
        if (Math.abs(y - startTouchY) > touchSlop) {
            touchState = TOUCH_STARTED;
        }
        if (velocityTracker != null) {
            velocityTracker.addMovement(event);
        }

        // scroll as appropriate
        if (touchState == TOUCH_STARTED) {
            final int scrollDelta = (int) (startTouchY - y);
            scrollTo(0, Math.max(0, Math.min(viewHeight, startTouchScrollY + scrollDelta)));
        }
        break;

    case MotionEvent.ACTION_CANCEL:
    case MotionEvent.ACTION_POINTER_UP:
    case MotionEvent.ACTION_UP:
        if (touchState == TOUCH_STARTED) {
            final int currentScrollY = getScrollY();

            // get velocity
            float velocity = 0;
            if (velocityTracker != null) {
                velocityTracker.computeCurrentVelocity(1000);
                velocity = VelocityTrackerCompat.getYVelocity(velocityTracker, pointerId);
                velocityTracker.recycle();
                velocityTracker = null;
            }

            // snap to final scroll position
            int target = startTouchScrollY;
            if ((Math.abs(velocity) > minimumflingVelocity) || (Math.abs(y - startTouchY) > (viewHeight / 2))) {
                if (velocity < 0) {
                    target = viewHeight;
                } else {
                    target = 0;
                }
            }
            scroller.startScroll(0, currentScrollY, 0, target - currentScrollY);
            invalidate();
            touchState = TOUCH_NONE;
        }
        break;
    }
    return true;
}