Android Open Source - paperchains Long Press Zoom Listener






From Project

Back to project page paperchains.

License

The source code is released under:

Apache License

If you think the Android project paperchains listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (c) 2010, Sony Ericsson Mobile Communication AB. All rights reserved.
 */*from  w  w  w . ja v  a 2  s . c o  m*/
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    * Redistributions of source code must retain the above copyright notice, this
 *      list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *    * Neither the name of the Sony Ericsson Mobile Communication AB nor the names
 *      of its contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.sonyericsson.zoom;

import android.content.Context;
import android.graphics.PointF;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;

/**
 * Listener for controlling zoom state through touch events
 */
public class LongPressZoomListener implements View.OnTouchListener {

  /**
   * Enum defining listener modes. Before the view is touched the listener is in the UNDEFINED mode. Once touch
   * starts
   * it can enter either one of the other two modes: If the user scrolls over the view the listener will enter PAN
   * mode, if the user lets his finger rest and makes a long press the listener will enter ZOOM mode.
   */
  private enum Mode {
    UNDEFINED, PAN, ZOOM, SCALE
  }

  /**
   * Current listener mode
   */
  private Mode mMode = Mode.UNDEFINED;

  /**
   * Zoom control to manipulate
   */
  private DynamicZoomControl mZoomControl;

  /**
   * Whether pan and zoom are enabled
   */
  private boolean mPanZoomEnabled;

  /**
   * X-coordinate of previously handled touch event
   */
  private float mX;

  /**
   * Y-coordinate of previously handled touch event
   */
  private float mY;

  /**
   * X-coordinate of latest down event
   */
  private float mDownX;

  /**
   * Y-coordinate of latest down event
   */
  private float mDownY;

  /**
   * Velocity tracker for touch events
   */
  private VelocityTracker mVelocityTracker;

  /**
   * Distance touch can wander before we think it's scrolling
   */
  private final int mScaledTouchSlop;

  /** Duration in ms before a press turns into a long press */
  // private final int mLongPressTimeout; // we now use the default platform "double tap to zoom"

  /**
   * Used to schedule a long press haptic feedback vibration
   */
  private boolean mPerformHapticFeedback;

  /**
   * Maximum velocity for fling
   */
  private final int mScaledMaximumFlingVelocity;

  /**
   * To fix issue on Nexus 5 (and possibly others) where prev ScaleGestureDetector values are the same as current
   */
  private float mPreviousScaleSpan = 0;

  private final ScaleGestureDetector mScaleDetector;

  /**
   * Creates a new instance
   *
   * @param context Application context
   */
  public LongPressZoomListener(Context context) {
    // mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
    mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    mScaledMaximumFlingVelocity = ViewConfiguration.get(context).getScaledMaximumFlingVelocity();
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    mPanZoomEnabled = true;
  }

  /**
   * Sets the zoom control to manipulate
   *
   * @param control Zoom control
   */
  public void setZoomControl(DynamicZoomControl control) {
    mZoomControl = control;
  }

  /**
   * Runnable that enters zoom mode
   */
  private final Runnable mLongPressRunnable = new Runnable() {
    public void run() {
      mMode = Mode.ZOOM;
      mPerformHapticFeedback = true;
    }
  };

  // returns the last position touched on the screen (for use with onClick)
  public PointF getLastTouchPoint() {
    return new PointF(mX, mY);
  }

  // implements View.OnTouchListener
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    final int action = event.getAction();
    final float x = event.getX();
    final float y = event.getY();

    if (mPerformHapticFeedback) {
      v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); // vibrate to indicate long press
      mPerformHapticFeedback = false;
    }

    mScaleDetector.onTouchEvent(event); // check for scaling on all touch events

    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(event);

    switch (action) {
      case MotionEvent.ACTION_DOWN:
        mZoomControl.stopFling();
        // TODO: disabled - confusing and non-standard behaviour (also bad with new double tap to zoom API)
        // v.postDelayed(mLongPressRunnable, mLongPressTimeout);
        mDownX = x;
        mDownY = y;
        mX = x;
        mY = y;
        break;

      case MotionEvent.ACTION_MOVE:
        final float dx = (x - mX) / v.getWidth();
        final float dy = (y - mY) / v.getHeight();

        // TODO: check for scale mode won't work due to pointer IDs/masking going to default - fix?
        if (mPanZoomEnabled) {
          if (mScaleDetector.isInProgress() || mMode == Mode.SCALE) {
            mMode = Mode.SCALE;
            if (mPreviousScaleSpan > 0 || mPreviousScaleSpan < 0) {
              mZoomControl.zoom(mScaleDetector.getCurrentSpan() / mPreviousScaleSpan,
                  mScaleDetector.getFocusX() / v.getWidth(), mScaleDetector.getFocusY() / v
                      .getHeight());
            }
            mPreviousScaleSpan = mScaleDetector.getCurrentSpan();
          } else if (mMode == Mode.ZOOM) {
            mZoomControl.zoom((float) Math.pow(20, -dy), mDownX / v.getWidth(), mDownY / v.getHeight());
          } else if (mMode == Mode.PAN) {
            mZoomControl.pan(-dx, -dy);
          } else {
            final float scrollX = mDownX - x;
            final float scrollY = mDownY - y;

            final float dist = (float) Math.sqrt(scrollX * scrollX + scrollY * scrollY);
            if (dist >= mScaledTouchSlop) {
              v.removeCallbacks(mLongPressRunnable);
              mMode = Mode.PAN;
            }
          }
        }

        mX = x;
        mY = y;
        break;

      case MotionEvent.ACTION_UP:
        if (mMode == Mode.PAN) {
          mVelocityTracker.computeCurrentVelocity(1000, mScaledMaximumFlingVelocity);
          mZoomControl.startFling(-mVelocityTracker.getXVelocity() / v.getWidth(),
              -mVelocityTracker.getYVelocity() / v.getHeight());
        } else {
          mZoomControl.startFling(0, 0);
        }
        mX = x;
        mY = y;
        // intentionally passing through to reset

      default:
        mVelocityTracker.recycle();
        mVelocityTracker = null;
        v.removeCallbacks(mLongPressRunnable);
        mMode = Mode.UNDEFINED;
        mPreviousScaleSpan = 0;
        break;

    }

    return false; // false so the normal onClick event works if we've allowed a click
  }

  public void setPanZoomEnabled(boolean enabled) {
    mPanZoomEnabled = enabled;
  }

  private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
      return true;
    }
  }

}




Java Source Code List

ac.robinson.paperchains.AudioRecorderCircleButton.java
ac.robinson.paperchains.PaperChainsActivity.java
ac.robinson.paperchains.PaperChainsView.java
ac.robinson.paperchains.SoundCloudLoginActivity.java
ac.robinson.paperchains.SoundCloudUploadTask.java
ac.robinson.paperchains.SoundCloudUrlFetcherTask.java
com.github.lassana.recorder.ApiHelper.java
com.github.lassana.recorder.AudioRecorder.java
com.github.lassana.recorder.Mp4ParserWrapper.java
com.sonyericsson.zoom.AspectQuotient.java
com.sonyericsson.zoom.DynamicZoomControl.java
com.sonyericsson.zoom.Dynamics.java
com.sonyericsson.zoom.LongPressZoomListener.java
com.sonyericsson.zoom.SpringDynamics.java
com.sonyericsson.zoom.ZoomState.java
com.soundcloud.playerapi.ApiWrapper.java
com.soundcloud.playerapi.CloudAPI.java
com.soundcloud.playerapi.CountingMultipartEntity.java
com.soundcloud.playerapi.DecompressingEntity.java
com.soundcloud.playerapi.Endpoints.java
com.soundcloud.playerapi.Env.java
com.soundcloud.playerapi.GzipDecompressingEntity.java
com.soundcloud.playerapi.Http.java
com.soundcloud.playerapi.OAuth2HttpRequestInterceptor.java
com.soundcloud.playerapi.OAuth2Scheme.java
com.soundcloud.playerapi.Params.java
com.soundcloud.playerapi.Request.java
com.soundcloud.playerapi.Stream.java
com.soundcloud.playerapi.Token.java