gt: 				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
context: package com.artifex.mupdfdemo;
  
  import java.util.ArrayList;
  
  import de.thecode.android.tazreader.R;
  
  import com.artifex.mupdfdemo.MuPDFCore.Cookie;
  
  import android.annotation.TargetApi;
  import android.app.AlertDialog;
  import android.content.ClipData;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.graphics.Bitmap;
  import android.graphics.Point;
  import android.graphics.PointF;
  import android.graphics.RectF;
  import android.net.Uri;
  import android.os.Build;
  import android.text.method.PasswordTransformationMethod;
  import android.view.LayoutInflater;
  import android.view.WindowManager;
  import android.view.inputmethod.EditorInfo;
  import android.widget.EditText;
  
  /* This enum should be kept in line with the corresponding C enum in mupdf.c */
  enum SignatureState {
  	NoSupport,
  	Unsigned,
  	Signed
  }
  
  abstract class PassClickResultVisitor {
  	public abstract void visitText(PassClickResultText result);
  	public abstract void visitChoice(PassClickResultChoice result);
  	public abstract void visitSignature(PassClickResultSignature result);
  }
  
  class PassClickResult {
  	public final boolean changed;
  
  	public PassClickResult(boolean _changed) {
  		changed = _changed;
  	}
  
  	public void acceptVisitor(PassClickResultVisitor visitor) {
  	}
  }
  
  class PassClickResultText extends PassClickResult {
  	public final String text;
  
  	public PassClickResultText(boolean _changed, String _text) {
  		super(_changed);
  		text = _text;
  	}
  
  	public void acceptVisitor(PassClickResultVisitor visitor) {
  		visitor.visitText(this);
  	}
  }
  
  class PassClickResultChoice extends PassClickResult {
  	public final String [] options;
  	public final String [] selected;
  
  	public PassClickResultChoice(boolean _changed, String [] _options, String [] _selected) {
  		super(_changed);
  		options = _options;
  		selected = _selected;
  	}
  
  	public void acceptVisitor(PassClickResultVisitor visitor) {
  		visitor.visitChoice(this);
  	}
  }
  
  class PassClickResultSignature extends PassClickResult {
  	public final SignatureState state;
  
  	public PassClickResultSignature(boolean _changed, int _state) {
  		super(_changed);
  		state = SignatureState.values()[_state];
  	}
  
  	public void acceptVisitor(PassClickResultVisitor visitor) {
  		visitor.visitSignature(this);
  	}
  }
  
  public class MuPDFPageView extends PageView implements MuPDFView {
  	final private FilePicker.FilePickerSupport mFilePickerSupport;
  	private final MuPDFCore mCore;
  	private AsyncTask<Void,Void,PassClickResult> mPassClick;
  	private RectF mWidgetAreas[];
  	private Annotation mAnnotations[];
  	private int mSelectedAnnotationIndex = -1;
  	private AsyncTask<Void,Void,RectF[]> mLoadWidgetAreas;
  	private AsyncTask<Void,Void,Annotation[]> mLoadAnnotations;
  	private AlertDialog.Builder mTextEntryBuilder;
  	private AlertDialog.Builder mChoiceEntryBuilder;
  	private AlertDialog.Builder mSigningDialogBuilder;
  	private AlertDialog.Builder mSignatureReportBuilder;
  	private AlertDialog.Builder mPasswordEntryBuilder;
  	private EditText mPasswordText;
  	private AlertDialog mTextEntry;
  	private AlertDialog mPasswordEntry;
  	private EditText mEditText;
  	private AsyncTask<String,Void,Boolean> mSetWidgetText;
  	private AsyncTask<String,Void,Void> mSetWidgetChoice;
  	private AsyncTask<PointF[],Void,Void> mAddStrikeOut;
  	private AsyncTask<PointF[][],Void,Void> mAddInk;
  	private AsyncTask<Integer,Void,Void> mDeleteAnnotation;
  	private AsyncTask<Void,Void,String> mCheckSignature;
  	private AsyncTask<Void,Void,Boolean> mSign;
  	private Runnable changeReporter;
  
  	public MuPDFPageView(Context c, FilePicker.FilePickerSupport filePickerSupport, MuPDFCore core, Point parentSize, Bitmap sharedHqBm) {
  		super(c, parentSize, sharedHqBm);
  		mFilePickerSupport = filePickerSupport;
  		mCore = core;
  		mTextEntryBuilder = new AlertDialog.Builder(c);
  		mTextEntryBuilder.setTitle(getContext().getString(R.string.fill_out_text_field));
  		LayoutInflater inflater = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  		mEditText = (EditText)inflater.inflate(R.layout.mupdf_textentry, null);
  		mTextEntryBuilder.setView(mEditText);
  		mTextEntryBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
  			public void onClick(DialogInterface dialog, int which) {
  				dialog.dismiss();
  			}
  		});
  		mTextEntryBuilder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
  			public void onClick(DialogInterface dialog, int which) {
  				mSetWidgetText = new AsyncTask<String,Void,Boolean> () {
  					@Override
  					protected Boolean doInBackground(String... arg0) {
  						return mCore.setFocusedWidgetText(mPageNumber, arg0[0]);
  					}
  					@Override
  					protected void onPostExecute(Boolean result) {
  						changeReporter.run();
  						if (!result)
  							invokeTextDialog(mEditText.getText().toString());
  					}
  				};
  
  				mSetWidgetText.execute(mEditText.getText().toString());
  			}
  		});
  		mTextEntry = mTextEntryBuilder.create();
  
  		mChoiceEntryBuilder = new AlertDialog.Builder(c);
  		mChoiceEntryBuilder.setTitle(getContext().getString(R.string.choose_value));
  
  		mSigningDialogBuilder = new AlertDialog.Builder(c);
  		mSigningDialogBuilder.setTitle("Select certificate and sign?");
  		mSigningDialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
  			@Override
  			public void onClick(DialogInterface dialog, int which) {
  				dialog.dismiss();
  			}
  		});
  		mSigningDialogBuilder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
  			@Override
  			public void onClick(DialogInterface dialog, int which) {
  				FilePicker picker = new FilePicker(mFilePickerSupport) {
  					@Override
  					void onPick(Uri uri) {
  						signWithKeyFile(uri);
  					}
  				};
  
  				picker.pick();
  			}
  		});
  
  		mSignatureReportBuilder = new AlertDialog.Builder(c);
  		mSignatureReportBuilder.setTitle("Signature checked");
  		mSignatureReportBuilder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
  			@Override
  			public void onClick(DialogInterface dialog, int which) {
  				dialog.dismiss();
  			}
  		});
  
  		mPasswordText = new EditText(c);
  		mPasswordText.setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
  		mPasswordText.setTransformationMethod(new PasswordTransformationMethod());
  
  		mPasswordEntryBuilder = new AlertDialog.Builder(c);
  		mPasswordEntryBuilder.setTitle(R.string.enter_password);
  		mPasswordEntryBuilder.setView(mPasswordText);
  		mPasswordEntryBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
  			@Override
  			public void onClick(DialogInterface dialog, int which) {
  				dialog.dismiss();
  			}
  		});
  
  		mPasswordEntry = mPasswordEntryBuilder.create();
  	}
  
  	private void signWithKeyFile(final Uri uri) {
  		mPasswordEntry.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
  		mPasswordEntry.setButton(AlertDialog.BUTTON_POSITIVE, "Sign", new DialogInterface.OnClickListener() {
  			@Override
  			public void onClick(DialogInterface dialog, int which) {
  				dialog.dismiss();
  				signWithKeyFileAndPassword(uri, mPasswordText.getText().toString());
  			}
  		});
  
  		mPasswordEntry.show();
  	}
  
  	private void signWithKeyFileAndPassword(final Uri uri, final String password) {
  		mSign = new AsyncTask<Void,Void,Boolean>() {
  			@Override
  			protected Boolean doInBackground(Void... params) {
  				return mCore.signFocusedSignature(Uri.decode(uri.getEncodedPath()), password);
  			}
  			@Override
  			protected void onPostExecute(Boolean result) {
  				if (result)
  				{
  					changeReporter.run();
  				}
  				else
  				{
  					mPasswordText.setText("");
  					signWithKeyFile(uri);
  				}
  			}
  
  		};
  
  		mSign.execute();
  	}
  
  	public LinkInfo hitLink(float x, float y) {
  		// Since link highlighting was implemented, the super class
  		// PageView has had sufficient information to be able to
  		// perform this method directly. Making that change would
  		// make MuPDFCore.hitLinkPage superfluous.
  		float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
  		float docRelX = (x - getLeft())/scale;
  		float docRelY = (y - getTop())/scale;
  
  		for (LinkInfo l: mLinks)
  			if (l.rect.contains(docRelX, docRelY))
  				return l;
  
  		return null;
  	}
  
  	private void invokeTextDialog(String text) {
  		mEditText.setText(text);
  		mTextEntry.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
  		mTextEntry.show();
  	}
  
  	private void invokeChoiceDialog(final String [] options) {
  		mChoiceEntryBuilder.setItems(options, new DialogInterface.OnClickListener() {
  			public void onClick(DialogInterface dialog, int which) {
  				mSetWidgetChoice = new AsyncTask<String,Void,Void>() {
  					@Override
  					protected Void doInBackground(String... params) {
  						String [] sel = {params[0]};
  						mCore.setFocusedWidgetChoiceSelected(sel);
  						return null;
  					}
  
  					@Override
  					protected void onPostExecute(Void result) {
  						changeReporter.run();
  					}
  				};
  
  				mSetWidgetChoice.execute(options[which]);
  			}
  		});
  		AlertDialog dialog = mChoiceEntryBuilder.create();
  		dialog.show();
  	}
  
  	private void invokeSignatureCheckingDialog() {
  		mCheckSignature = new AsyncTask<Void,Void,String> () {
  			@Override
  			protected String doInBackground(Void... params) {
  				return mCore.checkFocusedSignature();
  			}
  			@Override
  			protected void onPostExecute(String result) {
  				AlertDialog report = mSignatureReportBuilder.create();
  				report.setMessage(result);
  				report.show();
  			}
  		};
  
  		mCheckSignature.execute();
  	}
  
  	private void invokeSigningDialog() {
  		AlertDialog dialog = mSigningDialogBuilder.create();
  		dialog.show();
  	}
  
  	private void warnNoSignatureSupport() {
  		AlertDialog dialog = mSignatureReportBuilder.create();
  		dialog.setTitle("App built with no signature support");
  		dialog.show();
  	}
  
  	public void setChangeReporter(Runnable reporter) {
  		changeReporter = reporter;
  	}
  
  	public Hit passClickEvent(float x, float y) {
  		float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
  		final float docRelX = (x - getLeft())/scale;
  		final float docRelY = (y - getTop())/scale;
  		boolean hit = false;
  		int i;
  
  		if (mAnnotations != null) {
  			for (i = 0; i < mAnnotations.length; i++)
  				if (mAnnotations[i].contains(docRelX, docRelY)) {
  					hit = true;
  					break;
  				}
  
  			if (hit) {
  				switch (mAnnotations[i].type) {
  				case HIGHLIGHT:
  				case UNDERLINE:
  				case SQUIGGLY:
  				case STRIKEOUT:
  				case INK:
  					mSelectedAnnotationIndex = i;
  					setItemSelectBox(mAnnotations[i]);
  					return Hit.Annotation;
  				}
  			}
  		}
  
  		mSelectedAnnotationIndex = -1;
  		setItemSelectBox(null);
  
  		if (!mCore.javascriptSupported())
  			return Hit.Nothing;
  
  		if (mWidgetAreas != null) {
  			for (i = 0; i < mWidgetAreas.length && !hit; i++)
  				if (mWidgetAreas[i].contains(docRelX, docRelY))
  					hit = true;
  		}
  
  		if (hit) {
  			mPassClick = new AsyncTask<Void,Void,PassClickResult>() {
  				@Override
  				protected PassClickResult doInBackground(Void... arg0) {
  					return mCore.passClickEvent(mPageNumber, docRelX, docRelY);
  				}
  
  				@Override
  				protected void onPostExecute(PassClickResult result) {
  					if (result.changed) {
  						changeReporter.run();
  					}
  
  					result.acceptVisitor(new PassClickResultVisitor() {
  						@Override
  						public void visitText(PassClickResultText result) {
  							invokeTextDialog(result.text);
  						}
  
  						@Override
  						public void visitChoice(PassClickResultChoice result) {
  							invokeChoiceDialog(result.options);
  						}
  
  						@Override
  						public void visitSignature(PassClickResultSignature result) {
  							switch (result.state) {
  							case NoSupport:
  								warnNoSignatureSupport();
  								break;
  							case Unsigned:
  								invokeSigningDialog();
  								break;
  							case Signed:
  								invokeSignatureCheckingDialog();
  								break;
  							}
  						}
  					});
  				}
  			};
  
  			mPassClick.execute();
  			return Hit.Widget;
  		}
  
  		return Hit.Nothing;
  	}
  
  	@TargetApi(11)
  	public boolean copySelection() {
  		final StringBuilder text = new StringBuilder();
  
  		processSelectedText(new TextProcessor() {
  			StringBuilder line;
  
  			public void onStartLine() {
  				line = new StringBuilder();
  			}
  
  			public void onWord(TextWord word) {
  				if (line.length() > 0)
  					line.append(' ');
  				line.append(word.w);
  			}
  
  			public void onEndLine() {
  				if (text.length() > 0)
  					text.append('\n');
  				text.append(line);
  			}
  		});
  
  		if (text.length() == 0)
  			return false;
  
  		int currentApiVersion = android.os.Build.VERSION.SDK_INT;
  		if (currentApiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) {
  			android.content.ClipboardManager cm = (android.content.ClipboardManager)mContext.getSystemService(Context.CLIPBOARD_SERVICE);
  
  			cm.setPrimaryClip(ClipData.newPlainText("MuPDF", text));
  		} else {
  			android.text.ClipboardManager cm = (android.text.ClipboardManager)mContext.getSystemService(Context.CLIPBOARD_SERVICE);
  			cm.setText(text);
  		}
  
  		deselectText();
  
  		return true;
  	}
  
  	public boolean markupSelection(final Annotation.Type type) {
  		final ArrayList<PointF> quadPoints = new ArrayList<PointF>();
  		processSelectedText(new TextProcessor() {
  			RectF rect;
  
  			public void onStartLine() {
  				rect = new RectF();
  			}
  
  			public void onWord(TextWord word) {
  				rect.union(word);
  			}
  
  			public void onEndLine() {
  				if (!rect.isEmpty()) {
  					quadPoints.add(new PointF(rect.left, rect.bottom));
  					quadPoints.add(new PointF(rect.right, rect.bottom));
  					quadPoints.add(new PointF(rect.right, rect.top));
  					quadPoints.add(new PointF(rect.left, rect.top));
  				}
  			}
  		});
  
  		if (quadPoints.size() == 0)
  			return false;
  
  		mAddStrikeOut = new AsyncTask<PointF[],Void,Void>() {
  			@Override
  			protected Void doInBackground(PointF[]... params) {
  				addMarkup(params[0], type);
  				return null;
  			}
  
  			@Override
  			protected void onPostExecute(Void result) {
  				loadAnnotations();
  				update();
  			}
  		};
  
  		mAddStrikeOut.execute(quadPoints.toArray(new PointF[quadPoints.size()]));
  
  		deselectText();
  
  		return true;
  	}
  
  	public void deleteSelectedAnnotation() {
  		if (mSelectedAnnotationIndex != -1) {
  			if (mDeleteAnnotation != null)
  				mDeleteAnnotation.cancel(true);
  
  			mDeleteAnnotation = new AsyncTask<Integer,Void,Void>() {
  				@Override
  				protected Void doInBackground(Integer... params) {
  					mCore.deleteAnnotation(mPageNumber, params[0]);
  					return null;
  				}
  
  				@Override
  				protected void onPostExecute(Void result) {
  					loadAnnotations();
  					update();
  				}
  			};
  
  			mDeleteAnnotation.execute(mSelectedAnnotationIndex);
  
  			mSelectedAnnotationIndex = -1;
  			setItemSelectBox(null);
  		}
  	}
  
  	public void deselectAnnotation() {
  		mSelectedAnnotationIndex = -1;
  		setItemSelectBox(null);
  	}
  
  	public boolean saveDraw() {
  		PointF[][] path = getDraw();
  
  		if (path == null)
  			return false;
  
  		if (mAddInk != null) {
  			mAddInk.cancel(true);
  			mAddInk = null;
  		}
  		mAddInk = new AsyncTask<PointF[][],Void,Void>() {
  			@Override
  			protected Void doInBackground(PointF[][]... params) {
  				mCore.addInkAnnotation(mPageNumber, params[0]);
  				return null;
  			}
  
  			@Override
  			protected void onPostExecute(Void result) {
  				loadAnnotations();
  				update();
  			}
  
  		};
  
  		mAddInk.execute(getDraw());
  		cancelDraw();
  
  		return true;
  	}
  
  
  	@Override
  	protected CancellableTaskDefinition<Void, Void> getDrawPageTask(final Bitmap bm, final int sizeX, final int sizeY,
  			final int patchX, final int patchY, final int patchWidth, final int patchHeight) {
  		return new MuPDFCancellableTaskDefinition<Void, Void>(mCore) {
  			@Override
  			public Void doInBackground(MuPDFCore.Cookie cookie, Void ... params) {
  				// Workaround bug in Android Honeycomb 3.x, where the bitmap generation count
  				// is not incremented when drawing.
  				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
  						Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
  					bm.eraseColor(0);
  				mCore.drawPage(bm, mPageNumber, sizeX, sizeY, patchX, patchY, patchWidth, patchHeight, cookie);
  				return null;
  			}
  		};
  
  	}
  
  	protected CancellableTaskDefinition<Void, Void> getUpdatePageTask(final Bitmap bm, final int sizeX, final int sizeY,
  			final int patchX, final int patchY, final int patchWidth, final int patchHeight)
  	{
  		return new MuPDFCancellableTaskDefinition<Void, Void>(mCore) {
  
  			@Override
  			public Void doInBackground(MuPDFCore.Cookie cookie, Void ... params) {
  				// Workaround bug in Android Honeycomb 3.x, where the bitmap generation count
  				// is not incremented when drawing.
  