content: package com.agilie.gesturedetectors;
  
  import android.content.Context;
  import android.view.MotionEvent;
  
  /**
   * @author Almer Thie (code.almeros.com)
   * Copyright (c) 2013, Almer Thie (code.almeros.com)
   *
   * All rights reserved.
   *
   * 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.
   *
   * 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.
   */
  public class RotateGestureDetector extends TwoFingerGestureDetector {
  
  	/**
  	 * Listener which must be implemented which is used by RotateGestureDetector
  	 * to perform callbacks to any implementing class which is registered to a
  	 * RotateGestureDetector via the constructor.
  	 * 
  	 * @see SimpleOnRotateGestureListener
  	 */
  	public interface OnRotateGestureListener {
  		public boolean onRotate(RotateGestureDetector detector);
  		public boolean onRotateBegin(RotateGestureDetector detector);
  		public void onRotateEnd(RotateGestureDetector detector);
  	}
  	
  	/**
  	 * Helper class which may be extended and where the methods may be
  	 * implemented. This way it is not necessary to implement all methods
  	 * of OnRotateGestureListener.
  	 */
  	public static class SimpleOnRotateGestureListener implements OnRotateGestureListener {
  	    public boolean onRotate(RotateGestureDetector detector) {
  	        return false;
  	    }
  
  	    public boolean onRotateBegin(RotateGestureDetector detector) {
  	        return true;
  	    }
  
  	    public void onRotateEnd(RotateGestureDetector detector) {
  	    	// Do nothing, overridden implementation may be used
  	    }
  	}
  
      
      private final OnRotateGestureListener mListener;
      private boolean mSloppyGesture;
  
      public RotateGestureDetector(Context context, OnRotateGestureListener listener) {
      	super(context);
          mListener = listener;
      }
  
      @Override
      protected void handleStartProgressEvent(int actionCode, MotionEvent event){
          switch (actionCode) {
              case MotionEvent.ACTION_POINTER_DOWN:
                  // At least the second finger is on screen now
              	
                  resetState(); // In case we missed an UP/CANCEL event
                  mPrevEvent = MotionEvent.obtain(event);
                  mTimeDelta = 0;
                  
                  updateStateByEvent(event);
                  
                  // See if we have a sloppy gesture
                  mSloppyGesture = isSloppyGesture(event);
                  if(!mSloppyGesture){
                  	// No, start gesture now
                      mGestureInProgress = mListener.onRotateBegin(this);
                  } 
              	break;
              
              case MotionEvent.ACTION_MOVE:
                  if (!mSloppyGesture) {
                  	break;
                  }
                  
                  // See if we still have a sloppy gesture
                  mSloppyGesture = isSloppyGesture(event);
                  if(!mSloppyGesture){
                  	// No, start normal gesture now
                      mGestureInProgress = mListener.onRotateBegin(this);
                  }
      
                  break;
                  
              case MotionEvent.ACTION_POINTER_UP:
                  if (!mSloppyGesture) {
                  	break;
                  }
             
                  break; 
          }
      }
  
      
      @Override
      protected void handleInProgressEvent(int actionCode, MotionEvent event){ 	
          switch (actionCode) {
              case MotionEvent.ACTION_POINTER_UP:
                  // Gesture ended but 
                  updateStateByEvent(event);
  
                  if (!mSloppyGesture) {
                      mListener.onRotateEnd(this);
                  }
  
                  resetState();
                  break;
  
              case MotionEvent.ACTION_CANCEL:
                  if (!mSloppyGesture) {
                      mListener.onRotateEnd(this);
                  }
  
                  resetState();
                  break;
  
              case MotionEvent.ACTION_MOVE:
                  updateStateByEvent(event);
  
  				// Only accept the event if our relative pressure is within
  				// a certain limit. This can help filter shaky data as a
  				// finger is lifted.
                  if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
                      final boolean updatePrevious = mListener.onRotate(this);
                      if (updatePrevious) {
                          mPrevEvent.recycle();
                          mPrevEvent = MotionEvent.obtain(event);
                      }
                  }
                  break;
          }
      }
  
      @Override
      protected void resetState() {
          super.resetState();
          mSloppyGesture = false;
      }
  
  
      /**
       * Return the rotation difference from the previous rotate event to the current
       * event. 
       * 
       * @return The current rotation //difference in degrees.
       */
  	public float getRotationDegreesDelta() {
  		double diffRadians = Math.atan2(mPrevFingerDiffY, mPrevFingerDiffX) - Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX);
  		return (float) (diffRadians * 180 / Math.PI);
  	}
  }
  