gt: 		if (!mProcessTouch) return false;
context: /*
   * ComicsReader is an Android application to read comics
   * Copyright (C) 2011-2013 Cedric OCHS
   *
   * This program 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 program 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 program.  If not, see <http://www.gnu.org/licenses/>.
   *
   */
  
  package net.kervala.comicsreader;
  
  import net.kervala.comicsreader.AlbumThread.AlbumPageCallback;
  import android.app.Dialog;
  import android.content.Context;
  import android.content.Intent;
  import android.graphics.Bitmap;
  import android.graphics.PixelFormat;
  import android.os.Bundle;
  import android.util.Log;
  import android.view.GestureDetector;
  import android.view.InputDevice;
  import android.view.KeyEvent;
  import android.view.MotionEvent;
  import android.view.View;
  import android.view.Window;
  import android.view.WindowManager;
  import android.view.View.OnTouchListener;
  import android.view.animation.DecelerateInterpolator;
  import android.widget.Scroller;
  
  public class ViewerActivity extends CommonActivity implements OnTouchListener, FullScrollView.OnSizeChangedListener, AlbumPageCallback {
  	static final int PREVIOUS_PAGE = -1;
  	static final int CURRENT_PAGE = 0;
  	static final int NEXT_PAGE = 1;
  
  	private FullScrollView mScrollView;
  	private FullImageView mImageView;
  	
  	private AlbumThread mAlbumThread;
  
  	private int mMinPixelsBeforeSwitch = 0;
  	private int mFirstTouchPosX;
  	private int mFirstTouchPosY;
  	private int mPrevTouchPosX;
  	private boolean mProcessTouch = false;
  	private Scroller mScroller;
  	private Overlay mOverlay;
  	
  	private GestureDetector mGestureDetector;
  
  	@Override
  	public void onCreate(Bundle savedInstanceState) {
  		super.onCreate(savedInstanceState);
  		
  		setContentView(R.layout.viewer);
  
  		mScroller = new Scroller(this, new DecelerateInterpolator(1.0f));
  		mOverlay = new Overlay(this, mHandler);
  		
  		mScrollView = (FullScrollView) findViewById(R.id.scrollview);
  		mImageView = (FullImageView) findViewById(R.id.imageview);
  
  		mScrollView.setOnTouchListener(this);
  		registerForContextMenu(mScrollView);
  
  		mAlbumThread = new AlbumThread();
  		mAlbumThread.setAlbumPageCallback(this);
  		
  		mAlbumThread.loadPreferences();
  
  		Intent intent = getIntent();
  
  		mGestureDetector = new GestureDetector(this, new GestureListener());
  
  		if (Intent.ACTION_VIEW.equals(intent.getAction())) {
  			// open last page
  			mAlbumThread.open(intent.getData());
  		}
  	}
  	
  
  	private class GestureListener extends GestureDetector.SimpleOnGestureListener {
  
  		@Override
  		public boolean onDown(MotionEvent e) {
  			return true;
  		}
  
  		@Override
  		public boolean onDoubleTap(MotionEvent e) {
  			float x = e.getX();
  			float y = e.getY();
  
  			Log.d("ComicsReader", "Tapped at: (" + x + "," + y + ")");
  			mAlbumThread.cycleZoom();
  			changePage(mAlbumThread.getCurrentPage());
  
  			return true;
  		}
  	}
  
  	public void onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight) {
  		if (newWidth == oldWidth && newHeight == oldHeight) return;
  
  		int width = ComicsParameters.sScreenWidth;
  		int height = ComicsParameters.sScreenHeight;
  
  		ComicsParameters.sScreenWidth = newWidth;
  		ComicsParameters.sScreenHeight = newHeight;
  
  		if (mAlbumThread != null && mAlbumThread.isValid() && (width != newWidth || height != newHeight)) {
  			// force refreshing current page even if already loaded
  			mAlbumThread.updateCurrentPage(true);
  		}
  
  		mMinPixelsBeforeSwitch = newWidth >> 3;
  	}
  
  	@Override
  	protected void onResume() {
  		super.onResume();
  
  		mScrollView.setSizeChangedListener(this);
  		
  		if (mAlbumThread != null && mAlbumThread.isValid() && mImageView != null) {
  			// refresh current page only if not already loaded
  			mAlbumThread.updateCurrentPage(false);
  		}
  	}
  	
  	@Override
  	protected void onPause() {
  		super.onPause();
  
  		mScrollView.setSizeChangedListener(null);
  
  		// release all cached images in FullImageView
  		mImageView.reset();
  	}
  
  	@Override
  	protected void onDestroy() {
  		super.onDestroy();
  
  		mOverlay.remove();
  
  		if (mAlbumThread != null) {
  			mAlbumThread.exit();
  			mAlbumThread = null;
  		}
  		
  		// reset current open album
  		ComicsParameters.sCurrentOpenAlbum = null;
  	}
  
  	@Override
  	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  		switch(requestCode) {
  			case REQUEST_BOOKMARK:
  				if (resultCode == CommonActivity.RESULT_URL) {
  					openIntentFolder(data);
  				}
  			break;
  
  			case REQUEST_PREFERENCES:
  				mAlbumThread.loadPreferences();
  			break;
  		}
  	}
  	
  	@Override
  	protected Dialog onCreateDialog(int id) {
  		Dialog dialog = super.onCreateDialog(id);
  
  		if (dialog == null && mAlbumThread.isValid() && id == DIALOG_PAGES) {
  			dialog = new PagesDialog(this);
  		}
  
  		return dialog;
  	}
  
  	@Override
  	protected void onPrepareDialog (int id, Dialog dialog) {
  		super.onPrepareDialog(id, dialog);
  
  		// manage viewer specific dialogs
  		switch(id) {
  		case DIALOG_PAGES:
  			PagesDialog pagesDialog = (PagesDialog) dialog;
  
  			pagesDialog.setAlbum(mAlbumThread.getAlbum());
  			pagesDialog.setPage(mAlbumThread.getCurrentPage());
  			break;
  
  		default:
  			break;
  		}
  	}
  	
  	@Override
  	public boolean onSearchRequested() {
  		showDialog(DIALOG_PAGES);
  		return true;
  	}
  
  	@Override
  	public boolean onKeyDown(int keyCode, KeyEvent event) {
  		switch(keyCode) {
  		case KeyEvent.KEYCODE_DPAD_RIGHT:
  			scrollToNextPage();
  			return true;
  		case KeyEvent.KEYCODE_DPAD_LEFT:
  			scrollToPreviousPage();
  			return true;
  		case KeyEvent.KEYCODE_TAB:
  		case KeyEvent.KEYCODE_SEARCH:
  			showDialog(DIALOG_PAGES);
  			return true;
  		case KeyEvent.KEYCODE_BACK:
  			if (mAlbumThread != null) {
  				String mimeType = mAlbumThread.getAlbum() != null ? mAlbumThread.getAlbum().getMimeType():null;
  				Intent intent = getIntent();
  				intent.setDataAndType(mAlbumThread.getAlbumUri(), mimeType);
  				setResult(RESULT_FILE, intent);
  			}
  			finish();
  			return true;
  		}
  
  		return super.onKeyDown(keyCode, event);
  	}
  
  	@Override
  	public boolean onGenericMotionEvent(MotionEvent event) {
  		if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
  			switch (event.getAction()) {
  			case MotionEvent.ACTION_SCROLL:
  				// Process mouse scroll wheel movement
  				Log.d("ComicsReader", "AXIS_VSCROLL: " + new Float(event.getAxisValue(MotionEvent.AXIS_VSCROLL)).toString());
  				if (event.getAxisValue(MotionEvent.AXIS_VSCROLL) < 0)
  					scrollToNextPage();
  				else {
  					scrollToPreviousPage();
  				}
  				return true;
  			}
  		}
  		return super.onGenericMotionEvent(event);
  	}
  
  
  	public boolean onTouch(View v, MotionEvent event) {
  		mGestureDetector.onTouchEvent(event);
  		int touchPosX = (int) (event.getX());
  		int touchPosY = (int) (event.getY());
  
  		switch (event.getAction()) {
  			case MotionEvent.ACTION_UP:
  			return touchEnded(touchPosX, touchPosY);
  
  			case MotionEvent.ACTION_DOWN:
  			return touchBegan(touchPosX, touchPosY);
  
  			case MotionEvent.ACTION_MOVE:
  			return touchMoved(touchPosX, touchPosY);
  		}
  
  		return false;
  	}
  
  	private boolean touchBegan(int posX, int posY) {
  		if (mScroller.isFinished()){
  			mPrevTouchPosX = -1;
  			mFirstTouchPosX = posX;
  			mFirstTouchPosY = posY;
  		} else {
  			mScroller.forceFinished(true);
  			mProcessTouch = true;
  		}
  		
  		// make sure FullScrollView only receive touch events if scrollable
  		return !mScrollView.canScroll();
  	}
  
  	private boolean touchMoved(int posX, int posY) {
  		int fullDeltaX = posX - mFirstTouchPosX;
  		int fullDeltaY = posY - mFirstTouchPosY;
  		int absFullDeltaX = Math.abs(fullDeltaX);
  		int absFullDeltaY = Math.abs(fullDeltaY);
  
  		boolean scroll = false;
  
  		// horizontal fling
  		if (absFullDeltaX > (absFullDeltaY << 2)) {
  			int resistance = mAlbumThread.getEdgeResistance();
  			
  			if ((resistance < 1) || (absFullDeltaX > (mMinPixelsBeforeSwitch >> 2) * resistance)) {
  				int x = mImageView.getOffset() + mScrollView.getScrollX();
  				int w = mScrollView.getWidth();
  
  				if (x == 0 && fullDeltaX > 0 && !mAlbumThread.isFirstPage()) {
  					// left border, enable scroll to previous page
  					mAlbumThread.updatePreviousPage();
  					scroll = true;
  				} else if (x + w >= Math.max(ComicsParameters.sScreenWidth, mAlbumThread.getPageWidth()) && fullDeltaX < 0 &&  !mAlbumThread.isLastPage()) {
  					// right border, enable scroll to next page
  					mAlbumThread.updateNextPage();
  					scroll = true;
  				}
  			}
  		}
  
  		if (!mProcessTouch) {
  			// check if we should scroll horizontally
  			if (scroll) {
  				mScrollView.clearAnimation();
  
  				mProcessTouch = true;
  
  				return true;
  			}
  		} else {
  			if (mPrevTouchPosX == -1) {
  				mPrevTouchPosX = posX + mImageView.getOffset();
  			}
  
  			// negation since the screen moves in a direction opposite to that of the touch
  			int deltaX = -(posX - mPrevTouchPosX);
  			
  			mImageView.setOffset(deltaX);
  			
  			return true;
  		}
  
  		return false;
  	}
  
  	private boolean touchEnded(int posX, int posY) {
  