/** * Copyright (C) 2013- Iordan Iordanov * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ package com.undatech.opaque.input; import android.graphics.PointF; import android.view.MotionEvent; import android.os.Vibrator; import com.undatech.opaque.R; import com.undatech.opaque.RemoteCanvas; import com.undatech.opaque.RemoteCanvasActivity; public class InputHandlerDirectSwipePan extends InputHandlerGeneric { static final String TAG = "InputHandlerDirectSwipePan"; public static final String ID = "DirectSwipePan"; public InputHandlerDirectSwipePan(RemoteCanvasActivity activity, RemoteCanvas canvas, Vibrator myVibrator) { super(activity, canvas, myVibrator); } /* * (non-Javadoc) * @see com.undatech.opaque.input.InputHandler#getDescription() */ @Override public String getDescription() { return canvas.getResources().getString(R.string.input_method_direct_swipe_pan_description); } /* * (non-Javadoc) * @see com.undatech.opaque.input.InputHandler#getId() */ @Override public String getId() { return ID; } /* * (non-Javadoc) * @see android.view.GestureDetector.SimpleOnGestureListener#onDown(android.view.MotionEvent) */ @Override public boolean onDown(MotionEvent e) { panRepeater.stop(); return true; } /* * (non-Javadoc) * @see android.view.GestureDetector.SimpleOnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float) */ @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO: Workaround for Android 4.2. boolean twoFingers = false; if (e1 != null) twoFingers = (e1.getPointerCount() > 1); if (e2 != null) twoFingers = twoFingers || (e2.getPointerCount() > 1); // onFling called while scaling/swiping gesture is in effect. We ignore the event and pretend it was // consumed. This prevents the mouse pointer from flailing around while we are scaling. // Also, if one releases one finger slightly earlier than the other when scaling, it causes Android // to stick a spiteful onFling with a MASSIVE delta here. // This would cause the mouse pointer to jump to another place suddenly. // Hence, we ignore onFing after scaling until we lift all pointers up. if (twoFingers||disregardNextOnFling||inSwiping||inScaling||scalingJustFinished) { return true; } activity.showKbdIcon(); panRepeater.start(-velocityX, -velocityY); return true; } /* * (non-Javadoc) * @see android.view.GestureDetector.SimpleOnGestureListener#onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float) */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (!inScaling) { // onScroll called while swiping gesture is in effect. We ignore the event and pretend it was // consumed. This prevents the mouse pointer from flailing around while we are scaling. // Also, if one releases one finger slightly earlier than the other when scaling, it causes Android // to stick a spiteful onScroll with a MASSIVE delta here. // This would cause the mouse pointer to jump to another place suddenly. // Hence, we ignore onScroll after scaling until we lift all pointers up. boolean twoFingers = false; if (e1 != null) twoFingers = (e1.getPointerCount() > 1); if (e2 != null) twoFingers = twoFingers || (e2.getPointerCount() > 1); if (twoFingers||inSwiping||scalingJustFinished) return true; } if (!inScrolling) { inScrolling = true; distanceX = getSign(distanceX); distanceY = getSign(distanceY); distXQueue.clear(); distYQueue.clear(); } distXQueue.add(distanceX); distYQueue.add(distanceY); // Only after the first two events have arrived do we start using distanceX and Y // In order to effectively discard the last two events (which are typically unreliable // because of the finger lifting off). if (distXQueue.size() > 2) { distanceX = distXQueue.poll(); distanceY = distYQueue.poll(); } else { return true; } float scale = canvas.getZoomFactor(); activity.showKbdIcon(); canvas.relativePan((int)(distanceX*scale), (int)(distanceY*scale)); return true; } }