From d68576c3785572c1f5d41f83015b8fe6bbcbe9e8 Mon Sep 17 00:00:00 2001
From: Tor Andersson <tor.andersson@artifex.com>
Date: Wed, 30 Mar 2016 17:49:04 +0200
Subject: Reorganize java and android source.

platform/java and platform/android are reorganized:

   platform/java
      The new JNI Java classes, mupdf_native.{c,h}, Makefile and Makejar.

   platform/java/example
      The example desktop viewer classes.

   platform/android/viewer
      The original demo viewer.
      ndk-build is used to build libmupdf_java.so,
      making reference to mupdf_native.{c,h} in platform/java.
---
 .../com/artifex/mupdf/fitz/AndroidDrawDevice.java  |   22 -
 .../src/com/artifex/mupdfdemo/Annotation.java      |   18 -
 .../src/com/artifex/mupdfdemo/ArrayDeque.java      |  855 ------------
 .../src/com/artifex/mupdfdemo/AsyncTask.java       |  670 ---------
 .../artifex/mupdfdemo/CancellableAsyncTask.java    |   79 --
 .../mupdfdemo/CancellableTaskDefinition.java       |    8 -
 .../com/artifex/mupdfdemo/ChoosePDFActivity.java   |  227 ----
 .../com/artifex/mupdfdemo/ChoosePDFAdapter.java    |   66 -
 .../src/com/artifex/mupdfdemo/ChoosePDFItem.java   |   15 -
 .../android/src/com/artifex/mupdfdemo/Deque.java   |  554 --------
 .../src/com/artifex/mupdfdemo/FilePicker.java      |   21 -
 .../src/com/artifex/mupdfdemo/LinkInfo.java        |   14 -
 .../com/artifex/mupdfdemo/LinkInfoExternal.java    |   14 -
 .../com/artifex/mupdfdemo/LinkInfoInternal.java    |   14 -
 .../src/com/artifex/mupdfdemo/LinkInfoRemote.java  |   18 -
 .../src/com/artifex/mupdfdemo/LinkInfoVisitor.java |    7 -
 .../src/com/artifex/mupdfdemo/MuPDFActivity.java   | 1417 --------------------
 .../src/com/artifex/mupdfdemo/MuPDFAlert.java      |   21 -
 .../com/artifex/mupdfdemo/MuPDFAlertInternal.java  |   30 -
 .../mupdfdemo/MuPDFCancellableTaskDefinition.java  |   38 -
 .../src/com/artifex/mupdfdemo/MuPDFCore.java       |  402 ------
 .../com/artifex/mupdfdemo/MuPDFPageAdapter.java    |   87 --
 .../src/com/artifex/mupdfdemo/MuPDFPageView.java   |  692 ----------
 .../src/com/artifex/mupdfdemo/MuPDFReaderView.java |  276 ----
 .../com/artifex/mupdfdemo/MuPDFReflowAdapter.java  |   43 -
 .../src/com/artifex/mupdfdemo/MuPDFReflowView.java |  182 ---
 .../src/com/artifex/mupdfdemo/MuPDFView.java       |   33 -
 .../src/com/artifex/mupdfdemo/OutlineActivity.java |   31 -
 .../com/artifex/mupdfdemo/OutlineActivityData.java |   17 -
 .../src/com/artifex/mupdfdemo/OutlineAdapter.java  |   46 -
 .../src/com/artifex/mupdfdemo/OutlineItem.java     |   14 -
 .../src/com/artifex/mupdfdemo/PageView.java        |  698 ----------
 .../com/artifex/mupdfdemo/PrintDialogActivity.java |  145 --
 .../src/com/artifex/mupdfdemo/ReaderView.java      |  936 -------------
 .../artifex/mupdfdemo/SafeAnimatorInflater.java    |   35 -
 .../src/com/artifex/mupdfdemo/SearchTask.java      |  128 --
 .../com/artifex/mupdfdemo/SearchTaskResult.java    |   24 -
 .../src/com/artifex/mupdfdemo/Separation.java      |   15 -
 .../android/src/com/artifex/mupdfdemo/Stepper.java |   42 -
 .../src/com/artifex/mupdfdemo/TextChar.java        |   12 -
 .../src/com/artifex/mupdfdemo/TextWord.java        |   17 -
 .../src/com/artifex/mupdfdemo/WidgetType.java      |    9 -
 42 files changed, 7992 deletions(-)
 delete mode 100644 platform/android/src/com/artifex/mupdf/fitz/AndroidDrawDevice.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/Annotation.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/ArrayDeque.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/AsyncTask.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/CancellableAsyncTask.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/CancellableTaskDefinition.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/ChoosePDFActivity.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/ChoosePDFAdapter.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/ChoosePDFItem.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/Deque.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/FilePicker.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/LinkInfo.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/LinkInfoExternal.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/LinkInfoInternal.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/LinkInfoRemote.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/LinkInfoVisitor.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFAlert.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFAlertInternal.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFCancellableTaskDefinition.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFPageAdapter.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFReaderView.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFReflowAdapter.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFReflowView.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/MuPDFView.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/OutlineActivity.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/OutlineActivityData.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/OutlineAdapter.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/OutlineItem.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/PageView.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/PrintDialogActivity.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/ReaderView.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/SafeAnimatorInflater.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/SearchTask.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/SearchTaskResult.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/Separation.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/Stepper.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/TextChar.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/TextWord.java
 delete mode 100644 platform/android/src/com/artifex/mupdfdemo/WidgetType.java

(limited to 'platform/android/src/com/artifex')

diff --git a/platform/android/src/com/artifex/mupdf/fitz/AndroidDrawDevice.java b/platform/android/src/com/artifex/mupdf/fitz/AndroidDrawDevice.java
deleted file mode 100644
index 4a8daaa7..00000000
--- a/platform/android/src/com/artifex/mupdf/fitz/AndroidDrawDevice.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.artifex.mupdf.fitz;
-
-import android.graphics.Bitmap;
-
-public final class AndroidDrawDevice extends NativeDevice
-{
-	// NOT static.
-	private native long newNative(Bitmap bitmap, int pageX0, int pageY0, int pageX1, int pageY1, int patchX0, int patchY0, int patchX1, int patchY1);
-
-	// Construction
-	public AndroidDrawDevice(Bitmap bitmap, int pageX0, int pageY0, int pageX1, int pageY1, int patchX0, int patchY0, int patchX1, int patchY1)
-	{
-		super(0);
-		pointer = newNative(bitmap, pageX0, pageY0, pageX1, pageY1, patchX0, patchY0, patchX1, patchY1);
-	}
-
-	public AndroidDrawDevice(Bitmap bitmap, RectI page, RectI patch)
-	{
-		super(0);
-		pointer = newNative(bitmap, page.x0, page.y0, page.x1, page.y1, patch.x0, patch.y0, patch.x1, patch.y1);
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/Annotation.java b/platform/android/src/com/artifex/mupdfdemo/Annotation.java
deleted file mode 100644
index cf915524..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/Annotation.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.graphics.RectF;
-
-public class Annotation extends RectF {
-	enum Type {
-		TEXT, LINK, FREETEXT, LINE, SQUARE, CIRCLE, POLYGON, POLYLINE, HIGHLIGHT,
-		UNDERLINE, SQUIGGLY, STRIKEOUT, STAMP, CARET, INK, POPUP, FILEATTACHMENT,
-		SOUND, MOVIE, WIDGET, SCREEN, PRINTERMARK, TRAPNET, WATERMARK, A3D, UNKNOWN
-	}
-
-	public final Type type;
-
-	public Annotation(float x0, float y0, float x1, float y1, int _type) {
-		super(x0, y0, x1, y1);
-		type = _type == -1 ? Type.UNKNOWN : Type.values()[_type];
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/ArrayDeque.java b/platform/android/src/com/artifex/mupdfdemo/ArrayDeque.java
deleted file mode 100644
index 4f06ea41..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/ArrayDeque.java
+++ /dev/null
@@ -1,855 +0,0 @@
-/*
- * Written by Josh Bloch of Google Inc. and released to the public domain,
- * as explained at http://creativecommons.org/publicdomain/zero/1.0/.
- */
-
-package com.artifex.mupdfdemo;
-
-import java.util.AbstractCollection;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Queue;
-import java.util.Stack;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
-/**
- * Resizable-array implementation of the {@link Deque} interface.  Array
- * deques have no capacity restrictions; they grow as necessary to support
- * usage.  They are not thread-safe; in the absence of external
- * synchronization, they do not support concurrent access by multiple threads.
- * Null elements are prohibited.  This class is likely to be faster than
- * {@link Stack} when used as a stack, and faster than {@link LinkedList}
- * when used as a queue.
- *
- * <p>Most <tt>ArrayDeque</tt> operations run in amortized constant time.
- * Exceptions include {@link #remove(Object) remove}, {@link
- * #removeFirstOccurrence removeFirstOccurrence}, {@link #removeLastOccurrence
- * removeLastOccurrence}, {@link #contains contains}, {@link #iterator
- * iterator.remove()}, and the bulk operations, all of which run in linear
- * time.
- *
- * <p>The iterators returned by this class's <tt>iterator</tt> method are
- * <i>fail-fast</i>: If the deque is modified at any time after the iterator
- * is created, in any way except through the iterator's own <tt>remove</tt>
- * method, the iterator will generally throw a {@link
- * ConcurrentModificationException}.  Thus, in the face of concurrent
- * modification, the iterator fails quickly and cleanly, rather than risking
- * arbitrary, non-deterministic behavior at an undetermined time in the
- * future.
- *
- * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
- * as it is, generally speaking, impossible to make any hard guarantees in the
- * presence of unsynchronized concurrent modification.  Fail-fast iterators
- * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
- * Therefore, it would be wrong to write a program that depended on this
- * exception for its correctness: <i>the fail-fast behavior of iterators
- * should be used only to detect bugs.</i>
- *
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
- *
- * @author  Josh Bloch and Doug Lea
- * @since   1.6
- * @param <E> the type of elements held in this collection
- */
-public class ArrayDeque<E> extends AbstractCollection<E>
-                           implements Deque<E>, Cloneable, java.io.Serializable
-{
-    /**
-     * The array in which the elements of the deque are stored.
-     * The capacity of the deque is the length of this array, which is
-     * always a power of two. The array is never allowed to become
-     * full, except transiently within an addX method where it is
-     * resized (see doubleCapacity) immediately upon becoming full,
-     * thus avoiding head and tail wrapping around to equal each
-     * other.  We also guarantee that all array cells not holding
-     * deque elements are always null.
-     */
-    private transient Object[] elements;
-
-    /**
-     * The index of the element at the head of the deque (which is the
-     * element that would be removed by remove() or pop()); or an
-     * arbitrary number equal to tail if the deque is empty.
-     */
-    private transient int head;
-
-    /**
-     * The index at which the next element would be added to the tail
-     * of the deque (via addLast(E), add(E), or push(E)).
-     */
-    private transient int tail;
-
-    /**
-     * The minimum capacity that we'll use for a newly created deque.
-     * Must be a power of 2.
-     */
-    private static final int MIN_INITIAL_CAPACITY = 8;
-
-    // ******  Array allocation and resizing utilities ******
-
-    /**
-     * Allocate empty array to hold the given number of elements.
-     *
-     * @param numElements  the number of elements to hold
-     */
-    private void allocateElements(int numElements) {
-        int initialCapacity = MIN_INITIAL_CAPACITY;
-        // Find the best power of two to hold elements.
-        // Tests "<=" because arrays aren't kept full.
-        if (numElements >= initialCapacity) {
-            initialCapacity = numElements;
-            initialCapacity |= (initialCapacity >>>  1);
-            initialCapacity |= (initialCapacity >>>  2);
-            initialCapacity |= (initialCapacity >>>  4);
-            initialCapacity |= (initialCapacity >>>  8);
-            initialCapacity |= (initialCapacity >>> 16);
-            initialCapacity++;
-
-            if (initialCapacity < 0)   // Too many elements, must back off
-                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
-        }
-        elements = new Object[initialCapacity];
-    }
-
-    /**
-     * Double the capacity of this deque.  Call only when full, i.e.,
-     * when head and tail have wrapped around to become equal.
-     */
-    private void doubleCapacity() {
-        // assert head == tail;
-        int p = head;
-        int n = elements.length;
-        int r = n - p; // number of elements to the right of p
-        int newCapacity = n << 1;
-        if (newCapacity < 0)
-            throw new IllegalStateException("Sorry, deque too big");
-        Object[] a = new Object[newCapacity];
-        System.arraycopy(elements, p, a, 0, r);
-        System.arraycopy(elements, 0, a, r, p);
-        elements = a;
-        head = 0;
-        tail = n;
-    }
-
-    /**
-     * Copies the elements from our element array into the specified array,
-     * in order (from first to last element in the deque).  It is assumed
-     * that the array is large enough to hold all elements in the deque.
-     *
-     * @return its argument
-     */
-    private <T> T[] copyElements(T[] a) {
-        if (head < tail) {
-            System.arraycopy(elements, head, a, 0, size());
-        } else if (head > tail) {
-            int headPortionLen = elements.length - head;
-            System.arraycopy(elements, head, a, 0, headPortionLen);
-            System.arraycopy(elements, 0, a, headPortionLen, tail);
-        }
-        return a;
-    }
-
-    /**
-     * Constructs an empty array deque with an initial capacity
-     * sufficient to hold 16 elements.
-     */
-    public ArrayDeque() {
-        elements = new Object[16];
-    }
-
-    /**
-     * Constructs an empty array deque with an initial capacity
-     * sufficient to hold the specified number of elements.
-     *
-     * @param numElements  lower bound on initial capacity of the deque
-     */
-    public ArrayDeque(int numElements) {
-        allocateElements(numElements);
-    }
-
-    /**
-     * Constructs a deque containing the elements of the specified
-     * collection, in the order they are returned by the collection's
-     * iterator.  (The first element returned by the collection's
-     * iterator becomes the first element, or <i>front</i> of the
-     * deque.)
-     *
-     * @param c the collection whose elements are to be placed into the deque
-     * @throws NullPointerException if the specified collection is null
-     */
-    public ArrayDeque(Collection<? extends E> c) {
-        allocateElements(c.size());
-        addAll(c);
-    }
-
-    // The main insertion and extraction methods are addFirst,
-    // addLast, pollFirst, pollLast. The other methods are defined in
-    // terms of these.
-
-    /**
-     * Inserts the specified element at the front of this deque.
-     *
-     * @param e the element to add
-     * @throws NullPointerException if the specified element is null
-     */
-    public void addFirst(E e) {
-        if (e == null)
-            throw new NullPointerException("e == null");
-        elements[head = (head - 1) & (elements.length - 1)] = e;
-        if (head == tail)
-            doubleCapacity();
-    }
-
-    /**
-     * Inserts the specified element at the end of this deque.
-     *
-     * <p>This method is equivalent to {@link #add}.
-     *
-     * @param e the element to add
-     * @throws NullPointerException if the specified element is null
-     */
-    public void addLast(E e) {
-        if (e == null)
-            throw new NullPointerException("e == null");
-        elements[tail] = e;
-        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
-            doubleCapacity();
-    }
-
-    /**
-     * Inserts the specified element at the front of this deque.
-     *
-     * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Deque#offerFirst})
-     * @throws NullPointerException if the specified element is null
-     */
-    public boolean offerFirst(E e) {
-        addFirst(e);
-        return true;
-    }
-
-    /**
-     * Inserts the specified element at the end of this deque.
-     *
-     * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Deque#offerLast})
-     * @throws NullPointerException if the specified element is null
-     */
-    public boolean offerLast(E e) {
-        addLast(e);
-        return true;
-    }
-
-    /**
-     * @throws NoSuchElementException {@inheritDoc}
-     */
-    public E removeFirst() {
-        E x = pollFirst();
-        if (x == null)
-            throw new NoSuchElementException();
-        return x;
-    }
-
-    /**
-     * @throws NoSuchElementException {@inheritDoc}
-     */
-    public E removeLast() {
-        E x = pollLast();
-        if (x == null)
-            throw new NoSuchElementException();
-        return x;
-    }
-
-    public E pollFirst() {
-        int h = head;
-        @SuppressWarnings("unchecked") E result = (E) elements[h];
-        // Element is null if deque empty
-        if (result == null)
-            return null;
-        elements[h] = null;     // Must null out slot
-        head = (h + 1) & (elements.length - 1);
-        return result;
-    }
-
-    public E pollLast() {
-        int t = (tail - 1) & (elements.length - 1);
-        @SuppressWarnings("unchecked") E result = (E) elements[t];
-        if (result == null)
-            return null;
-        elements[t] = null;
-        tail = t;
-        return result;
-    }
-
-    /**
-     * @throws NoSuchElementException {@inheritDoc}
-     */
-    public E getFirst() {
-        @SuppressWarnings("unchecked") E result = (E) elements[head];
-        if (result == null)
-            throw new NoSuchElementException();
-        return result;
-    }
-
-    /**
-     * @throws NoSuchElementException {@inheritDoc}
-     */
-    public E getLast() {
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[(tail - 1) & (elements.length - 1)];
-        if (result == null)
-            throw new NoSuchElementException();
-        return result;
-    }
-
-    public E peekFirst() {
-        @SuppressWarnings("unchecked") E result = (E) elements[head];
-        // elements[head] is null if deque empty
-        return result;
-    }
-
-    public E peekLast() {
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[(tail - 1) & (elements.length - 1)];
-        return result;
-    }
-
-    /**
-     * Removes the first occurrence of the specified element in this
-     * deque (when traversing the deque from head to tail).
-     * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the first element <tt>e</tt> such that
-     * <tt>o.equals(e)</tt> (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
-     * (or equivalently, if this deque changed as a result of the call).
-     *
-     * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if the deque contained the specified element
-     */
-    public boolean removeFirstOccurrence(Object o) {
-        if (o == null)
-            return false;
-        int mask = elements.length - 1;
-        int i = head;
-        Object x;
-        while ( (x = elements[i]) != null) {
-            if (o.equals(x)) {
-                delete(i);
-                return true;
-            }
-            i = (i + 1) & mask;
-        }
-        return false;
-    }
-
-    /**
-     * Removes the last occurrence of the specified element in this
-     * deque (when traversing the deque from head to tail).
-     * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the last element <tt>e</tt> such that
-     * <tt>o.equals(e)</tt> (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
-     * (or equivalently, if this deque changed as a result of the call).
-     *
-     * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if the deque contained the specified element
-     */
-    public boolean removeLastOccurrence(Object o) {
-        if (o == null)
-            return false;
-        int mask = elements.length - 1;
-        int i = (tail - 1) & mask;
-        Object x;
-        while ( (x = elements[i]) != null) {
-            if (o.equals(x)) {
-                delete(i);
-                return true;
-            }
-            i = (i - 1) & mask;
-        }
-        return false;
-    }
-
-    // *** Queue methods ***
-
-    /**
-     * Inserts the specified element at the end of this deque.
-     *
-     * <p>This method is equivalent to {@link #addLast}.
-     *
-     * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Collection#add})
-     * @throws NullPointerException if the specified element is null
-     */
-    public boolean add(E e) {
-        addLast(e);
-        return true;
-    }
-
-    /**
-     * Inserts the specified element at the end of this deque.
-     *
-     * <p>This method is equivalent to {@link #offerLast}.
-     *
-     * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Queue#offer})
-     * @throws NullPointerException if the specified element is null
-     */
-    public boolean offer(E e) {
-        return offerLast(e);
-    }
-
-    /**
-     * Retrieves and removes the head of the queue represented by this deque.
-     *
-     * This method differs from {@link #poll poll} only in that it throws an
-     * exception if this deque is empty.
-     *
-     * <p>This method is equivalent to {@link #removeFirst}.
-     *
-     * @return the head of the queue represented by this deque
-     * @throws NoSuchElementException {@inheritDoc}
-     */
-    public E remove() {
-        return removeFirst();
-    }
-
-    /**
-     * Retrieves and removes the head of the queue represented by this deque
-     * (in other words, the first element of this deque), or returns
-     * <tt>null</tt> if this deque is empty.
-     *
-     * <p>This method is equivalent to {@link #pollFirst}.
-     *
-     * @return the head of the queue represented by this deque, or
-     *         <tt>null</tt> if this deque is empty
-     */
-    public E poll() {
-        return pollFirst();
-    }
-
-    /**
-     * Retrieves, but does not remove, the head of the queue represented by
-     * this deque.  This method differs from {@link #peek peek} only in
-     * that it throws an exception if this deque is empty.
-     *
-     * <p>This method is equivalent to {@link #getFirst}.
-     *
-     * @return the head of the queue represented by this deque
-     * @throws NoSuchElementException {@inheritDoc}
-     */
-    public E element() {
-        return getFirst();
-    }
-
-    /**
-     * Retrieves, but does not remove, the head of the queue represented by
-     * this deque, or returns <tt>null</tt> if this deque is empty.
-     *
-     * <p>This method is equivalent to {@link #peekFirst}.
-     *
-     * @return the head of the queue represented by this deque, or
-     *         <tt>null</tt> if this deque is empty
-     */
-    public E peek() {
-        return peekFirst();
-    }
-
-    // *** Stack methods ***
-
-    /**
-     * Pushes an element onto the stack represented by this deque.  In other
-     * words, inserts the element at the front of this deque.
-     *
-     * <p>This method is equivalent to {@link #addFirst}.
-     *
-     * @param e the element to push
-     * @throws NullPointerException if the specified element is null
-     */
-    public void push(E e) {
-        addFirst(e);
-    }
-
-    /**
-     * Pops an element from the stack represented by this deque.  In other
-     * words, removes and returns the first element of this deque.
-     *
-     * <p>This method is equivalent to {@link #removeFirst()}.
-     *
-     * @return the element at the front of this deque (which is the top
-     *         of the stack represented by this deque)
-     * @throws NoSuchElementException {@inheritDoc}
-     */
-    public E pop() {
-        return removeFirst();
-    }
-
-    private void checkInvariants() {
-        // assert elements[tail] == null;
-        // assert head == tail ? elements[head] == null :
-        //     (elements[head] != null &&
-        //      elements[(tail - 1) & (elements.length - 1)] != null);
-        // assert elements[(head - 1) & (elements.length - 1)] == null;
-    }
-
-    /**
-     * Removes the element at the specified position in the elements array,
-     * adjusting head and tail as necessary.  This can result in motion of
-     * elements backwards or forwards in the array.
-     *
-     * <p>This method is called delete rather than remove to emphasize
-     * that its semantics differ from those of {@link List#remove(int)}.
-     *
-     * @return true if elements moved backwards
-     */
-    private boolean delete(int i) {
-        //checkInvariants();
-        final Object[] elements = this.elements;
-        final int mask = elements.length - 1;
-        final int h = head;
-        final int t = tail;
-        final int front = (i - h) & mask;
-        final int back  = (t - i) & mask;
-
-        // Invariant: head <= i < tail mod circularity
-        if (front >= ((t - h) & mask))
-            throw new ConcurrentModificationException();
-
-        // Optimize for least element motion
-        if (front < back) {
-            if (h <= i) {
-                System.arraycopy(elements, h, elements, h + 1, front);
-            } else { // Wrap around
-                System.arraycopy(elements, 0, elements, 1, i);
-                elements[0] = elements[mask];
-                System.arraycopy(elements, h, elements, h + 1, mask - h);
-            }
-            elements[h] = null;
-            head = (h + 1) & mask;
-            return false;
-        } else {
-            if (i < t) { // Copy the null tail as well
-                System.arraycopy(elements, i + 1, elements, i, back);
-                tail = t - 1;
-            } else { // Wrap around
-                System.arraycopy(elements, i + 1, elements, i, mask - i);
-                elements[mask] = elements[0];
-                System.arraycopy(elements, 1, elements, 0, t);
-                tail = (t - 1) & mask;
-            }
-            return true;
-        }
-    }
-
-    // *** Collection Methods ***
-
-    /**
-     * Returns the number of elements in this deque.
-     *
-     * @return the number of elements in this deque
-     */
-    public int size() {
-        return (tail - head) & (elements.length - 1);
-    }
-
-    /**
-     * Returns <tt>true</tt> if this deque contains no elements.
-     *
-     * @return <tt>true</tt> if this deque contains no elements
-     */
-    public boolean isEmpty() {
-        return head == tail;
-    }
-
-    /**
-     * Returns an iterator over the elements in this deque.  The elements
-     * will be ordered from first (head) to last (tail).  This is the same
-     * order that elements would be dequeued (via successive calls to
-     * {@link #remove} or popped (via successive calls to {@link #pop}).
-     *
-     * @return an iterator over the elements in this deque
-     */
-    public Iterator<E> iterator() {
-        return new DeqIterator();
-    }
-
-    public Iterator<E> descendingIterator() {
-        return new DescendingIterator();
-    }
-
-    private class DeqIterator implements Iterator<E> {
-        /**
-         * Index of element to be returned by subsequent call to next.
-         */
-        private int cursor = head;
-
-        /**
-         * Tail recorded at construction (also in remove), to stop
-         * iterator and also to check for comodification.
-         */
-        private int fence = tail;
-
-        /**
-         * Index of element returned by most recent call to next.
-         * Reset to -1 if element is deleted by a call to remove.
-         */
-        private int lastRet = -1;
-
-        public boolean hasNext() {
-            return cursor != fence;
-        }
-
-        public E next() {
-            if (cursor == fence)
-                throw new NoSuchElementException();
-            @SuppressWarnings("unchecked") E result = (E) elements[cursor];
-            // This check doesn't catch all possible comodifications,
-            // but does catch the ones that corrupt traversal
-            if (tail != fence || result == null)
-                throw new ConcurrentModificationException();
-            lastRet = cursor;
-            cursor = (cursor + 1) & (elements.length - 1);
-            return result;
-        }
-
-        public void remove() {
-            if (lastRet < 0)
-                throw new IllegalStateException();
-            if (delete(lastRet)) { // if left-shifted, undo increment in next()
-                cursor = (cursor - 1) & (elements.length - 1);
-                fence = tail;
-            }
-            lastRet = -1;
-        }
-    }
-
-    private class DescendingIterator implements Iterator<E> {
-        /*
-         * This class is nearly a mirror-image of DeqIterator, using
-         * tail instead of head for initial cursor, and head instead of
-         * tail for fence.
-         */
-        private int cursor = tail;
-        private int fence = head;
-        private int lastRet = -1;
-
-        public boolean hasNext() {
-            return cursor != fence;
-        }
-
-        public E next() {
-            if (cursor == fence)
-                throw new NoSuchElementException();
-            cursor = (cursor - 1) & (elements.length - 1);
-            @SuppressWarnings("unchecked") E result = (E) elements[cursor];
-            if (head != fence || result == null)
-                throw new ConcurrentModificationException();
-            lastRet = cursor;
-            return result;
-        }
-
-        public void remove() {
-            if (lastRet < 0)
-                throw new IllegalStateException();
-            if (!delete(lastRet)) {
-                cursor = (cursor + 1) & (elements.length - 1);
-                fence = head;
-            }
-            lastRet = -1;
-        }
-    }
-
-    /**
-     * Returns <tt>true</tt> if this deque contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this deque contains
-     * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.
-     *
-     * @param o object to be checked for containment in this deque
-     * @return <tt>true</tt> if this deque contains the specified element
-     */
-    public boolean contains(Object o) {
-        if (o == null)
-            return false;
-        int mask = elements.length - 1;
-        int i = head;
-        Object x;
-        while ( (x = elements[i]) != null) {
-            if (o.equals(x))
-                return true;
-            i = (i + 1) & mask;
-        }
-        return false;
-    }
-
-    /**
-     * Removes a single instance of the specified element from this deque.
-     * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the first element <tt>e</tt> such that
-     * <tt>o.equals(e)</tt> (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
-     * (or equivalently, if this deque changed as a result of the call).
-     *
-     * <p>This method is equivalent to {@link #removeFirstOccurrence}.
-     *
-     * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if this deque contained the specified element
-     */
-    public boolean remove(Object o) {
-        return removeFirstOccurrence(o);
-    }
-
-    /**
-     * Removes all of the elements from this deque.
-     * The deque will be empty after this call returns.
-     */
-    public void clear() {
-        int h = head;
-        int t = tail;
-        if (h != t) { // clear all cells
-            head = tail = 0;
-            int i = h;
-            int mask = elements.length - 1;
-            do {
-                elements[i] = null;
-                i = (i + 1) & mask;
-            } while (i != t);
-        }
-    }
-
-    /**
-     * Returns an array containing all of the elements in this deque
-     * in proper sequence (from first to last element).
-     *
-     * <p>The returned array will be "safe" in that no references to it are
-     * maintained by this deque.  (In other words, this method must allocate
-     * a new array).  The caller is thus free to modify the returned array.
-     *
-     * <p>This method acts as bridge between array-based and collection-based
-     * APIs.
-     *
-     * @return an array containing all of the elements in this deque
-     */
-    public Object[] toArray() {
-        return copyElements(new Object[size()]);
-    }
-
-    /**
-     * Returns an array containing all of the elements in this deque in
-     * proper sequence (from first to last element); the runtime type of the
-     * returned array is that of the specified array.  If the deque fits in
-     * the specified array, it is returned therein.  Otherwise, a new array
-     * is allocated with the runtime type of the specified array and the
-     * size of this deque.
-     *
-     * <p>If this deque fits in the specified array with room to spare
-     * (i.e., the array has more elements than this deque), the element in
-     * the array immediately following the end of the deque is set to
-     * <tt>null</tt>.
-     *
-     * <p>Like the {@link #toArray()} method, this method acts as bridge between
-     * array-based and collection-based APIs.  Further, this method allows
-     * precise control over the runtime type of the output array, and may,
-     * under certain circumstances, be used to save allocation costs.
-     *
-     * <p>Suppose <tt>x</tt> is a deque known to contain only strings.
-     * The following code can be used to dump the deque into a newly
-     * allocated array of <tt>String</tt>:
-     *
-     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
-     *
-     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
-     * <tt>toArray()</tt>.
-     *
-     * @param a the array into which the elements of the deque are to
-     *          be stored, if it is big enough; otherwise, a new array of the
-     *          same runtime type is allocated for this purpose
-     * @return an array containing all of the elements in this deque
-     * @throws ArrayStoreException if the runtime type of the specified array
-     *         is not a supertype of the runtime type of every element in
-     *         this deque
-     * @throws NullPointerException if the specified array is null
-     */
-    @SuppressWarnings("unchecked")
-    public <T> T[] toArray(T[] a) {
-        int size = size();
-        if (a.length < size)
-            a = (T[])java.lang.reflect.Array.newInstance(
-                    a.getClass().getComponentType(), size);
-        copyElements(a);
-        if (a.length > size)
-            a[size] = null;
-        return a;
-    }
-
-    // *** Object methods ***
-
-    /**
-     * Returns a copy of this deque.
-     *
-     * @return a copy of this deque
-     */
-    public ArrayDeque<E> clone() {
-        try {
-            @SuppressWarnings("unchecked")
-            ArrayDeque<E> result = (ArrayDeque<E>) super.clone();
-            result.elements = Arrays.copyOf(elements, elements.length);
-            return result;
-
-        } catch (CloneNotSupportedException e) {
-            throw new AssertionError();
-        }
-    }
-
-    /**
-     * Appease the serialization gods.
-     */
-    private static final long serialVersionUID = 2340985798034038923L;
-
-    /**
-     * Serialize this deque.
-     *
-     * @serialData The current size (<tt>int</tt>) of the deque,
-     * followed by all of its elements (each an object reference) in
-     * first-to-last order.
-     */
-    private void writeObject(java.io.ObjectOutputStream s)
-            throws java.io.IOException {
-        s.defaultWriteObject();
-
-        // Write out size
-        s.writeInt(size());
-
-        // Write out elements in order.
-        int mask = elements.length - 1;
-        for (int i = head; i != tail; i = (i + 1) & mask)
-            s.writeObject(elements[i]);
-    }
-
-    /**
-     * Deserialize this deque.
-     */
-    private void readObject(java.io.ObjectInputStream s)
-            throws java.io.IOException, ClassNotFoundException {
-        s.defaultReadObject();
-
-        // Read in size and allocate array
-        int size = s.readInt();
-        allocateElements(size);
-        head = 0;
-        tail = size;
-
-        // Read in all elements in the proper order.
-        for (int i = 0; i < size; i++)
-            elements[i] = s.readObject();
-    }
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/AsyncTask.java b/platform/android/src/com/artifex/mupdfdemo/AsyncTask.java
deleted file mode 100644
index b370794c..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/AsyncTask.java
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.artifex.mupdfdemo;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import android.os.Process;
-import android.os.Handler;
-import android.os.Message;
-
-/**
- * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to
- * perform background operations and publish results on the UI thread without
- * having to manipulate threads and/or handlers.</p>
- *
- * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
- * and does not constitute a generic threading framework. AsyncTasks should ideally be
- * used for short operations (a few seconds at the most.) If you need to keep threads
- * running for long periods of time, it is highly recommended you use the various APIs
- * provided by the <code>java.util.concurrent</code> pacakge such as {@link Executor},
- * {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
- *
- * <p>An asynchronous task is defined by a computation that runs on a background thread and
- * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
- * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
- * and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
- * <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about using tasks and threads, read the
- * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
- * Threads</a> developer guide.</p>
- * </div>
- *
- * <h2>Usage</h2>
- * <p>AsyncTask must be subclassed to be used. The subclass will override at least
- * one method ({@link #doInBackground}), and most often will override a
- * second one ({@link #onPostExecute}.)</p>
- *
- * <p>Here is an example of subclassing:</p>
- * <pre class="prettyprint">
- * private class DownloadFilesTask extends AsyncTask&lt;URL, Integer, Long&gt; {
- *     protected Long doInBackground(URL... urls) {
- *         int count = urls.length;
- *         long totalSize = 0;
- *         for (int i = 0; i < count; i++) {
- *             totalSize += Downloader.downloadFile(urls[i]);
- *             publishProgress((int) ((i / (float) count) * 100));
- *             // Escape early if cancel() is called
- *             if (isCancelled()) break;
- *         }
- *         return totalSize;
- *     }
- *
- *     protected void onProgressUpdate(Integer... progress) {
- *         setProgressPercent(progress[0]);
- *     }
- *
- *     protected void onPostExecute(Long result) {
- *         showDialog("Downloaded " + result + " bytes");
- *     }
- * }
- * </pre>
- *
- * <p>Once created, a task is executed very simply:</p>
- * <pre class="prettyprint">
- * new DownloadFilesTask().execute(url1, url2, url3);
- * </pre>
- *
- * <h2>AsyncTask's generic types</h2>
- * <p>The three types used by an asynchronous task are the following:</p>
- * <ol>
- *     <li><code>Params</code>, the type of the parameters sent to the task upon
- *     execution.</li>
- *     <li><code>Progress</code>, the type of the progress units published during
- *     the background computation.</li>
- *     <li><code>Result</code>, the type of the result of the background
- *     computation.</li>
- * </ol>
- * <p>Not all types are always used by an asynchronous task. To mark a type as unused,
- * simply use the type {@link Void}:</p>
- * <pre>
- * private class MyTask extends AsyncTask&lt;Void, Void, Void&gt; { ... }
- * </pre>
- *
- * <h2>The 4 steps</h2>
- * <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
- * <ol>
- *     <li>{@link #onPreExecute()}, invoked on the UI thread before the task
- *     is executed. This step is normally used to setup the task, for instance by
- *     showing a progress bar in the user interface.</li>
- *     <li>{@link #doInBackground}, invoked on the background thread
- *     immediately after {@link #onPreExecute()} finishes executing. This step is used
- *     to perform background computation that can take a long time. The parameters
- *     of the asynchronous task are passed to this step. The result of the computation must
- *     be returned by this step and will be passed back to the last step. This step
- *     can also use {@link #publishProgress} to publish one or more units
- *     of progress. These values are published on the UI thread, in the
- *     {@link #onProgressUpdate} step.</li>
- *     <li>{@link #onProgressUpdate}, invoked on the UI thread after a
- *     call to {@link #publishProgress}. The timing of the execution is
- *     undefined. This method is used to display any form of progress in the user
- *     interface while the background computation is still executing. For instance,
- *     it can be used to animate a progress bar or show logs in a text field.</li>
- *     <li>{@link #onPostExecute}, invoked on the UI thread after the background
- *     computation finishes. The result of the background computation is passed to
- *     this step as a parameter.</li>
- * </ol>
- *
- * <h2>Cancelling a task</h2>
- * <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking
- * this method will cause subsequent calls to {@link #isCancelled()} to return true.
- * After invoking this method, {@link #onCancelled(Object)}, instead of
- * {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}
- * returns. To ensure that a task is cancelled as quickly as possible, you should always
- * check the return value of {@link #isCancelled()} periodically from
- * {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p>
- *
- * <h2>Threading rules</h2>
- * <p>There are a few threading rules that must be followed for this class to
- * work properly:</p>
- * <ul>
- *     <li>The AsyncTask class must be loaded on the UI thread. This is done
- *     automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
- *     <li>The task instance must be created on the UI thread.</li>
- *     <li>{@link #execute} must be invoked on the UI thread.</li>
- *     <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
- *     {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
- *     <li>The task can be executed only once (an exception will be thrown if
- *     a second execution is attempted.)</li>
- * </ul>
- *
- * <h2>Memory observability</h2>
- * <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following
- * operations are safe without explicit synchronizations.</p>
- * <ul>
- *     <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them
- *     in {@link #doInBackground}.
- *     <li>Set member fields in {@link #doInBackground}, and refer to them in
- *     {@link #onProgressUpdate} and {@link #onPostExecute}.
- * </ul>
- *
- * <h2>Order of execution</h2>
- * <p>When first introduced, AsyncTasks were executed serially on a single background
- * thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
- * to a pool of threads allowing multiple tasks to operate in parallel. Starting with
- * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single
- * thread to avoid common application errors caused by parallel execution.</p>
- * <p>If you truly want parallel execution, you can invoke
- * {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with
- * {@link #THREAD_POOL_EXECUTOR}.</p>
- */
-public abstract class AsyncTask<Params, Progress, Result> {
-    private static final String LOG_TAG = "AsyncTask";
-
-    private static final int CORE_POOL_SIZE = 5;
-    private static final int MAXIMUM_POOL_SIZE = 128;
-    private static final int KEEP_ALIVE = 1;
-
-    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
-        private final AtomicInteger mCount = new AtomicInteger(1);
-
-        public Thread newThread(Runnable r) {
-            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
-        }
-    };
-
-    private static final BlockingQueue<Runnable> sPoolWorkQueue =
-            new LinkedBlockingQueue<Runnable>(10);
-
-    /**
-     * An {@link Executor} that can be used to execute tasks in parallel.
-     */
-    public static final Executor THREAD_POOL_EXECUTOR
-            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
-                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
-
-    /**
-     * An {@link Executor} that executes tasks one at a time in serial
-     * order.  This serialization is global to a particular process.
-     */
-    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
-
-    private static final int MESSAGE_POST_RESULT = 0x1;
-    private static final int MESSAGE_POST_PROGRESS = 0x2;
-
-    private static final InternalHandler sHandler = new InternalHandler();
-
-    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
-    private final WorkerRunnable<Params, Result> mWorker;
-    private final FutureTask<Result> mFuture;
-
-    private volatile Status mStatus = Status.PENDING;
-
-    private final AtomicBoolean mCancelled = new AtomicBoolean();
-    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
-
-    private static class SerialExecutor implements Executor {
-        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
-        Runnable mActive;
-
-        public synchronized void execute(final Runnable r) {
-            mTasks.offer(new Runnable() {
-                public void run() {
-                    try {
-                        r.run();
-                    } finally {
-                        scheduleNext();
-                    }
-                }
-            });
-            if (mActive == null) {
-                scheduleNext();
-            }
-        }
-
-        protected synchronized void scheduleNext() {
-            if ((mActive = mTasks.poll()) != null) {
-                THREAD_POOL_EXECUTOR.execute(mActive);
-            }
-        }
-    }
-
-    /**
-     * Indicates the current status of the task. Each status will be set only once
-     * during the lifetime of a task.
-     */
-    public enum Status {
-        /**
-         * Indicates that the task has not been executed yet.
-         */
-        PENDING,
-        /**
-         * Indicates that the task is running.
-         */
-        RUNNING,
-        /**
-         * Indicates that {@link AsyncTask#onPostExecute} has finished.
-         */
-        FINISHED,
-    }
-
-    /** @hide Used to force static handler to be created. */
-    public static void init() {
-        sHandler.getLooper();
-    }
-
-    /** @hide */
-    public static void setDefaultExecutor(Executor exec) {
-        sDefaultExecutor = exec;
-    }
-
-    /**
-     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
-     */
-    public AsyncTask() {
-        mWorker = new WorkerRunnable<Params, Result>() {
-            public Result call() throws Exception {
-                mTaskInvoked.set(true);
-
-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                //noinspection unchecked
-                return postResult(doInBackground(mParams));
-            }
-        };
-
-        mFuture = new FutureTask<Result>(mWorker) {
-            @Override
-            protected void done() {
-                try {
-                    postResultIfNotInvoked(get());
-                } catch (InterruptedException e) {
-                    android.util.Log.w(LOG_TAG, e);
-                } catch (ExecutionException e) {
-                    throw new RuntimeException("An error occured while executing doInBackground()",
-                            e.getCause());
-                } catch (CancellationException e) {
-                    postResultIfNotInvoked(null);
-                }
-            }
-        };
-    }
-
-    private void postResultIfNotInvoked(Result result) {
-        final boolean wasTaskInvoked = mTaskInvoked.get();
-        if (!wasTaskInvoked) {
-            postResult(result);
-        }
-    }
-
-    private Result postResult(Result result) {
-        @SuppressWarnings("unchecked")
-        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
-                new AsyncTaskResult<Result>(this, result));
-        message.sendToTarget();
-        return result;
-    }
-
-    /**
-     * Returns the current status of this task.
-     *
-     * @return The current status.
-     */
-    public final Status getStatus() {
-        return mStatus;
-    }
-
-    /**
-     * Override this method to perform a computation on a background thread. The
-     * specified parameters are the parameters passed to {@link #execute}
-     * by the caller of this task.
-     *
-     * This method can call {@link #publishProgress} to publish updates
-     * on the UI thread.
-     *
-     * @param params The parameters of the task.
-     *
-     * @return A result, defined by the subclass of this task.
-     *
-     * @see #onPreExecute()
-     * @see #onPostExecute
-     * @see #publishProgress
-     */
-    protected abstract Result doInBackground(Params... params);
-
-    /**
-     * Runs on the UI thread before {@link #doInBackground}.
-     *
-     * @see #onPostExecute
-     * @see #doInBackground
-     */
-    protected void onPreExecute() {
-    }
-
-    /**
-     * <p>Runs on the UI thread after {@link #doInBackground}. The
-     * specified result is the value returned by {@link #doInBackground}.</p>
-     *
-     * <p>This method won't be invoked if the task was cancelled.</p>
-     *
-     * @param result The result of the operation computed by {@link #doInBackground}.
-     *
-     * @see #onPreExecute
-     * @see #doInBackground
-     * @see #onCancelled(Object)
-     */
-    @SuppressWarnings({"UnusedDeclaration"})
-    protected void onPostExecute(Result result) {
-    }
-
-    /**
-     * Runs on the UI thread after {@link #publishProgress} is invoked.
-     * The specified values are the values passed to {@link #publishProgress}.
-     *
-     * @param values The values indicating progress.
-     *
-     * @see #publishProgress
-     * @see #doInBackground
-     */
-    @SuppressWarnings({"UnusedDeclaration"})
-    protected void onProgressUpdate(Progress... values) {
-    }
-
-    /**
-     * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
-     * {@link #doInBackground(Object[])} has finished.</p>
-     *
-     * <p>The default implementation simply invokes {@link #onCancelled()} and
-     * ignores the result. If you write your own implementation, do not call
-     * <code>super.onCancelled(result)</code>.</p>
-     *
-     * @param result The result, if any, computed in
-     *               {@link #doInBackground(Object[])}, can be null
-     *
-     * @see #cancel(boolean)
-     * @see #isCancelled()
-     */
-    @SuppressWarnings({"UnusedParameters"})
-    protected void onCancelled(Result result) {
-        onCancelled();
-    }
-
-    /**
-     * <p>Applications should preferably override {@link #onCancelled(Object)}.
-     * This method is invoked by the default implementation of
-     * {@link #onCancelled(Object)}.</p>
-     *
-     * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
-     * {@link #doInBackground(Object[])} has finished.</p>
-     *
-     * @see #onCancelled(Object)
-     * @see #cancel(boolean)
-     * @see #isCancelled()
-     */
-    protected void onCancelled() {
-    }
-
-    /**
-     * Returns <tt>true</tt> if this task was cancelled before it completed
-     * normally. If you are calling {@link #cancel(boolean)} on the task,
-     * the value returned by this method should be checked periodically from
-     * {@link #doInBackground(Object[])} to end the task as soon as possible.
-     *
-     * @return <tt>true</tt> if task was cancelled before it completed
-     *
-     * @see #cancel(boolean)
-     */
-    public final boolean isCancelled() {
-        return mCancelled.get();
-    }
-
-    /**
-     * <p>Attempts to cancel execution of this task.  This attempt will
-     * fail if the task has already completed, already been cancelled,
-     * or could not be cancelled for some other reason. If successful,
-     * and this task has not started when <tt>cancel</tt> is called,
-     * this task should never run. If the task has already started,
-     * then the <tt>mayInterruptIfRunning</tt> parameter determines
-     * whether the thread executing this task should be interrupted in
-     * an attempt to stop the task.</p>
-     *
-     * <p>Calling this method will result in {@link #onCancelled(Object)} being
-     * invoked on the UI thread after {@link #doInBackground(Object[])}
-     * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
-     * is never invoked. After invoking this method, you should check the
-     * value returned by {@link #isCancelled()} periodically from
-     * {@link #doInBackground(Object[])} to finish the task as early as
-     * possible.</p>
-     *
-     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
-     *        task should be interrupted; otherwise, in-progress tasks are allowed
-     *        to complete.
-     *
-     * @return <tt>false</tt> if the task could not be cancelled,
-     *         typically because it has already completed normally;
-     *         <tt>true</tt> otherwise
-     *
-     * @see #isCancelled()
-     * @see #onCancelled(Object)
-     */
-    public final boolean cancel(boolean mayInterruptIfRunning) {
-        mCancelled.set(true);
-        return mFuture.cancel(mayInterruptIfRunning);
-    }
-
-    /**
-     * Waits if necessary for the computation to complete, and then
-     * retrieves its result.
-     *
-     * @return The computed result.
-     *
-     * @throws CancellationException If the computation was cancelled.
-     * @throws ExecutionException If the computation threw an exception.
-     * @throws InterruptedException If the current thread was interrupted
-     *         while waiting.
-     */
-    public final Result get() throws InterruptedException, ExecutionException {
-        return mFuture.get();
-    }
-
-    /**
-     * Waits if necessary for at most the given time for the computation
-     * to complete, and then retrieves its result.
-     *
-     * @param timeout Time to wait before cancelling the operation.
-     * @param unit The time unit for the timeout.
-     *
-     * @return The computed result.
-     *
-     * @throws CancellationException If the computation was cancelled.
-     * @throws ExecutionException If the computation threw an exception.
-     * @throws InterruptedException If the current thread was interrupted
-     *         while waiting.
-     * @throws TimeoutException If the wait timed out.
-     */
-    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
-            ExecutionException, TimeoutException {
-        return mFuture.get(timeout, unit);
-    }
-
-    /**
-     * Executes the task with the specified parameters. The task returns
-     * itself (this) so that the caller can keep a reference to it.
-     *
-     * <p>Note: this function schedules the task on a queue for a single background
-     * thread or pool of threads depending on the platform version.  When first
-     * introduced, AsyncTasks were executed serially on a single background thread.
-     * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
-     * to a pool of threads allowing multiple tasks to operate in parallel. Starting
-     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
-     * executed on a single thread to avoid common application errors caused
-     * by parallel execution.  If you truly want parallel execution, you can use
-     * the {@link #executeOnExecutor} version of this method
-     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
-     * on its use.
-     *
-     * <p>This method must be invoked on the UI thread.
-     *
-     * @param params The parameters of the task.
-     *
-     * @return This instance of AsyncTask.
-     *
-     * @throws IllegalStateException If {@link #getStatus()} returns either
-     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
-     *
-     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
-     * @see #execute(Runnable)
-     */
-    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
-        return executeOnExecutor(sDefaultExecutor, params);
-    }
-
-    /**
-     * Executes the task with the specified parameters. The task returns
-     * itself (this) so that the caller can keep a reference to it.
-     *
-     * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
-     * allow multiple tasks to run in parallel on a pool of threads managed by
-     * AsyncTask, however you can also use your own {@link Executor} for custom
-     * behavior.
-     *
-     * <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
-     * a thread pool is generally <em>not</em> what one wants, because the order
-     * of their operation is not defined.  For example, if these tasks are used
-     * to modify any state in common (such as writing a file due to a button click),
-     * there are no guarantees on the order of the modifications.
-     * Without careful work it is possible in rare cases for the newer version
-     * of the data to be over-written by an older one, leading to obscure data
-     * loss and stability issues.  Such changes are best
-     * executed in serial; to guarantee such work is serialized regardless of
-     * platform version you can use this function with {@link #SERIAL_EXECUTOR}.
-     *
-     * <p>This method must be invoked on the UI thread.
-     *
-     * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a
-     *              convenient process-wide thread pool for tasks that are loosely coupled.
-     * @param params The parameters of the task.
-     *
-     * @return This instance of AsyncTask.
-     *
-     * @throws IllegalStateException If {@link #getStatus()} returns either
-     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
-     *
-     * @see #execute(Object[])
-     */
-    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
-            Params... params) {
-        if (mStatus != Status.PENDING) {
-            switch (mStatus) {
-                case RUNNING:
-                    throw new IllegalStateException("Cannot execute task:"
-                            + " the task is already running.");
-                case FINISHED:
-                    throw new IllegalStateException("Cannot execute task:"
-                            + " the task has already been executed "
-                            + "(a task can be executed only once)");
-            }
-        }
-
-        mStatus = Status.RUNNING;
-
-        onPreExecute();
-
-        mWorker.mParams = params;
-        exec.execute(mFuture);
-
-        return this;
-    }
-
-    /**
-     * Convenience version of {@link #execute(Object...)} for use with
-     * a simple Runnable object. See {@link #execute(Object[])} for more
-     * information on the order of execution.
-     *
-     * @see #execute(Object[])
-     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
-     */
-    public static void execute(Runnable runnable) {
-        sDefaultExecutor.execute(runnable);
-    }
-
-    /**
-     * This method can be invoked from {@link #doInBackground} to
-     * publish updates on the UI thread while the background computation is
-     * still running. Each call to this method will trigger the execution of
-     * {@link #onProgressUpdate} on the UI thread.
-     *
-     * {@link #onProgressUpdate} will note be called if the task has been
-     * canceled.
-     *
-     * @param values The progress values to update the UI with.
-     *
-     * @see #onProgressUpdate
-     * @see #doInBackground
-     */
-    protected final void publishProgress(Progress... values) {
-        if (!isCancelled()) {
-            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
-                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
-        }
-    }
-
-    private void finish(Result result) {
-        if (isCancelled()) {
-            onCancelled(result);
-        } else {
-            onPostExecute(result);
-        }
-        mStatus = Status.FINISHED;
-    }
-
-    private static class InternalHandler extends Handler {
-        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
-        @Override
-        public void handleMessage(Message msg) {
-            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
-            switch (msg.what) {
-                case MESSAGE_POST_RESULT:
-                    // There is only one result
-                    result.mTask.finish(result.mData[0]);
-                    break;
-                case MESSAGE_POST_PROGRESS:
-                    result.mTask.onProgressUpdate(result.mData);
-                    break;
-            }
-        }
-    }
-
-    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
-        Params[] mParams;
-    }
-
-    @SuppressWarnings({"RawUseOfParameterizedType"})
-    private static class AsyncTaskResult<Data> {
-        final AsyncTask mTask;
-        final Data[] mData;
-
-        AsyncTaskResult(AsyncTask task, Data... data) {
-            mTask = task;
-            mData = data;
-        }
-    }
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/CancellableAsyncTask.java b/platform/android/src/com/artifex/mupdfdemo/CancellableAsyncTask.java
deleted file mode 100644
index fcb1b744..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/CancellableAsyncTask.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-
-// Ideally this would be a subclass of AsyncTask, however the cancel() method is final, and cannot
-// be overridden. I felt that having two different, but similar cancel methods was a bad idea.
-public class CancellableAsyncTask<Params, Result>
-{
-	private final AsyncTask<Params, Void, Result> asyncTask;
-	private final CancellableTaskDefinition<Params, Result> ourTask;
-
-	public void onPreExecute()
-	{
-
-	}
-
-	public void onPostExecute(Result result)
-	{
-
-	}
-
-	public CancellableAsyncTask(final CancellableTaskDefinition<Params, Result> task)
-	{
-		if (task == null)
-				throw new IllegalArgumentException();
-
-		this.ourTask = task;
-		asyncTask = new AsyncTask<Params, Void, Result>()
-				{
-					@Override
-					protected Result doInBackground(Params... params)
-					{
-						return task.doInBackground(params);
-					}
-
-					@Override
-					protected void onPreExecute()
-					{
-						CancellableAsyncTask.this.onPreExecute();
-					}
-
-					@Override
-					protected void onPostExecute(Result result)
-					{
-						CancellableAsyncTask.this.onPostExecute(result);
-						task.doCleanup();
-					}
-				};
-	}
-
-	public void cancelAndWait()
-	{
-		this.asyncTask.cancel(true);
-		ourTask.doCancel();
-
-		try
-		{
-			this.asyncTask.get();
-		}
-		catch (InterruptedException e)
-		{
-		}
-		catch (ExecutionException e)
-		{
-		}
-		catch (CancellationException e)
-		{
-		}
-
-		ourTask.doCleanup();
-	}
-
-	public void execute(Params ... params)
-	{
-		asyncTask.execute(params);
-	}
-
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/CancellableTaskDefinition.java b/platform/android/src/com/artifex/mupdfdemo/CancellableTaskDefinition.java
deleted file mode 100644
index 62b04f30..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/CancellableTaskDefinition.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public interface CancellableTaskDefinition <Params, Result>
-{
-	public Result doInBackground(Params ... params);
-	public void doCancel();
-	public void doCleanup();
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/ChoosePDFActivity.java b/platform/android/src/com/artifex/mupdfdemo/ChoosePDFActivity.java
deleted file mode 100644
index f6068bac..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/ChoosePDFActivity.java
+++ /dev/null
@@ -1,227 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
-
-import android.app.AlertDialog;
-import android.app.ListActivity;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.FileObserver;
-import android.os.Handler;
-import android.view.View;
-import android.widget.ListView;
-
-enum Purpose {
-	PickPDF,
-	PickKeyFile
-}
-
-public class ChoosePDFActivity extends ListActivity {
-	static public final String PICK_KEY_FILE = "com.artifex.mupdfdemo.PICK_KEY_FILE";
-	static private File  mDirectory;
-	static private Map<String, Integer> mPositions = new HashMap<String, Integer>();
-	private File         mParent;
-	private File []      mDirs;
-	private File []      mFiles;
-	private Handler	     mHandler;
-	private Runnable     mUpdateFiles;
-	private ChoosePDFAdapter adapter;
-	private Purpose      mPurpose;
-
-	@Override
-	protected void onCreate(Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-
-		mPurpose = PICK_KEY_FILE.equals(getIntent().getAction()) ? Purpose.PickKeyFile : Purpose.PickPDF;
-
-
-		String storageState = Environment.getExternalStorageState();
-
-		if (!Environment.MEDIA_MOUNTED.equals(storageState)
-				&& !Environment.MEDIA_MOUNTED_READ_ONLY.equals(storageState))
-		{
-			AlertDialog.Builder builder = new AlertDialog.Builder(this);
-			builder.setTitle(R.string.no_media_warning);
-			builder.setMessage(R.string.no_media_hint);
-			AlertDialog alert = builder.create();
-			alert.setButton(AlertDialog.BUTTON_POSITIVE,getString(R.string.dismiss),
-					new OnClickListener() {
-						public void onClick(DialogInterface dialog, int which) {
-							finish();
-						}
-					});
-			alert.show();
-			return;
-		}
-
-		if (mDirectory == null)
-			mDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
-
-		// Create a list adapter...
-		adapter = new ChoosePDFAdapter(getLayoutInflater());
-		setListAdapter(adapter);
-
-		// ...that is updated dynamically when files are scanned
-		mHandler = new Handler();
-		mUpdateFiles = new Runnable() {
-			public void run() {
-				Resources res = getResources();
-				String appName = res.getString(R.string.app_name);
-				String version = res.getString(R.string.version);
-				String title = res.getString(R.string.picker_title_App_Ver_Dir);
-				setTitle(String.format(title, appName, version, mDirectory));
-
-				mParent = mDirectory.getParentFile();
-
-				mDirs = mDirectory.listFiles(new FileFilter() {
-
-					public boolean accept(File file) {
-						return file.isDirectory();
-					}
-				});
-				if (mDirs == null)
-					mDirs = new File[0];
-
-				mFiles = mDirectory.listFiles(new FileFilter() {
-
-					public boolean accept(File file) {
-						if (file.isDirectory())
-							return false;
-						String fname = file.getName().toLowerCase();
-						switch (mPurpose) {
-						case PickPDF:
-							if (fname.endsWith(".pdf"))
-								return true;
-							if (fname.endsWith(".xps"))
-								return true;
-							if (fname.endsWith(".cbz"))
-								return true;
-							if (fname.endsWith(".epub"))
-								return true;
-							if (fname.endsWith(".png"))
-								return true;
-							if (fname.endsWith(".jpe"))
-								return true;
-							if (fname.endsWith(".jpeg"))
-								return true;
-							if (fname.endsWith(".jpg"))
-								return true;
-							if (fname.endsWith(".jfif"))
-								return true;
-							if (fname.endsWith(".jfif-tbnl"))
-								return true;
-							if (fname.endsWith(".tif"))
-								return true;
-							if (fname.endsWith(".tiff"))
-								return true;
-							return false;
-						case PickKeyFile:
-							if (fname.endsWith(".pfx"))
-								return true;
-							return false;
-						default:
-							return false;
-						}
-					}
-				});
-				if (mFiles == null)
-					mFiles = new File[0];
-
-				Arrays.sort(mFiles, new Comparator<File>() {
-					public int compare(File arg0, File arg1) {
-						return arg0.getName().compareToIgnoreCase(arg1.getName());
-					}
-				});
-
-				Arrays.sort(mDirs, new Comparator<File>() {
-					public int compare(File arg0, File arg1) {
-						return arg0.getName().compareToIgnoreCase(arg1.getName());
-					}
-				});
-
-				adapter.clear();
-				if (mParent != null)
-					adapter.add(new ChoosePDFItem(ChoosePDFItem.Type.PARENT, getString(R.string.parent_directory)));
-				for (File f : mDirs)
-					adapter.add(new ChoosePDFItem(ChoosePDFItem.Type.DIR, f.getName()));
-				for (File f : mFiles)
-					adapter.add(new ChoosePDFItem(ChoosePDFItem.Type.DOC, f.getName()));
-
-				lastPosition();
-			}
-		};
-
-		// Start initial file scan...
-		mHandler.post(mUpdateFiles);
-
-		// ...and observe the directory and scan files upon changes.
-		FileObserver observer = new FileObserver(mDirectory.getPath(), FileObserver.CREATE | FileObserver.DELETE) {
-			public void onEvent(int event, String path) {
-				mHandler.post(mUpdateFiles);
-			}
-		};
-		observer.startWatching();
-	}
-
-	private void lastPosition() {
-		String p = mDirectory.getAbsolutePath();
-		if (mPositions.containsKey(p))
-			getListView().setSelection(mPositions.get(p));
-	}
-
-	@Override
-	protected void onListItemClick(ListView l, View v, int position, long id) {
-		super.onListItemClick(l, v, position, id);
-
-		mPositions.put(mDirectory.getAbsolutePath(), getListView().getFirstVisiblePosition());
-
-		if (position < (mParent == null ? 0 : 1)) {
-			mDirectory = mParent;
-			mHandler.post(mUpdateFiles);
-			return;
-		}
-
-		position -= (mParent == null ? 0 : 1);
-
-		if (position < mDirs.length) {
-			mDirectory = mDirs[position];
-			mHandler.post(mUpdateFiles);
-			return;
-		}
-
-		position -= mDirs.length;
-
-		Uri uri = Uri.fromFile(mFiles[position]);
-		Intent intent = new Intent(this,MuPDFActivity.class);
-		intent.setAction(Intent.ACTION_VIEW);
-		intent.setData(uri);
-		switch (mPurpose) {
-		case PickPDF:
-			// Start an activity to display the PDF file
-			startActivity(intent);
-			break;
-		case PickKeyFile:
-			// Return the uri to the caller
-			setResult(RESULT_OK, intent);
-			finish();
-			break;
-		}
-	}
-
-	@Override
-	protected void onPause() {
-		super.onPause();
-		if (mDirectory != null)
-			mPositions.put(mDirectory.getAbsolutePath(), getListView().getFirstVisiblePosition());
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/ChoosePDFAdapter.java b/platform/android/src/com/artifex/mupdfdemo/ChoosePDFAdapter.java
deleted file mode 100644
index 0b3c6418..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/ChoosePDFAdapter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import java.util.LinkedList;
-
-import android.graphics.Color;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-public class ChoosePDFAdapter extends BaseAdapter {
-	private final LinkedList<ChoosePDFItem> mItems;
-	private final LayoutInflater mInflater;
-
-	public ChoosePDFAdapter(LayoutInflater inflater) {
-		mInflater = inflater;
-		mItems = new LinkedList<ChoosePDFItem>();
-	}
-
-	public void clear() {
-		mItems.clear();
-	}
-
-	public void add(ChoosePDFItem item) {
-		mItems.add(item);
-		notifyDataSetChanged();
-	}
-
-	public int getCount() {
-		return mItems.size();
-	}
-
-	public Object getItem(int i) {
-		return null;
-	}
-
-	public long getItemId(int arg0) {
-		return 0;
-	}
-
-	private int iconForType(ChoosePDFItem.Type type) {
-		switch (type) {
-		case PARENT: return R.drawable.ic_arrow_up;
-		case DIR: return R.drawable.ic_dir;
-		case DOC: return R.drawable.ic_doc;
-		default: return 0;
-		}
-	}
-
-	public View getView(int position, View convertView, ViewGroup parent) {
-		View v;
-		if (convertView == null) {
-			v = mInflater.inflate(R.layout.picker_entry, null);
-		} else {
-			v = convertView;
-		}
-		ChoosePDFItem item = mItems.get(position);
-		((TextView)v.findViewById(R.id.name)).setText(item.name);
-		((ImageView)v.findViewById(R.id.icon)).setImageResource(iconForType(item.type));
-		((ImageView)v.findViewById(R.id.icon)).setColorFilter(Color.argb(255, 0, 0, 0));
-		return v;
-	}
-
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/ChoosePDFItem.java b/platform/android/src/com/artifex/mupdfdemo/ChoosePDFItem.java
deleted file mode 100644
index de6e1d52..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/ChoosePDFItem.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public class ChoosePDFItem {
-	enum Type {
-		PARENT, DIR, DOC
-	}
-
-	final public Type type;
-	final public String name;
-
-	public ChoosePDFItem (Type t, String n) {
-		type = t;
-		name = n;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/Deque.java b/platform/android/src/com/artifex/mupdfdemo/Deque.java
deleted file mode 100644
index 4bb176b2..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/Deque.java
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * Written by Doug Lea and Josh Bloch with assistance from members of
- * JCP JSR-166 Expert Group and released to the public domain, as explained
- * at http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package com.artifex.mupdfdemo;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Queue;
-import java.util.Stack;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
-/**
- * A linear collection that supports element insertion and removal at
- * both ends.  The name <i>deque</i> is short for "double ended queue"
- * and is usually pronounced "deck".  Most <tt>Deque</tt>
- * implementations place no fixed limits on the number of elements
- * they may contain, but this interface supports capacity-restricted
- * deques as well as those with no fixed size limit.
- *
- * <p>This interface defines methods to access the elements at both
- * ends of the deque.  Methods are provided to insert, remove, and
- * examine the element.  Each of these methods exists in two forms:
- * one throws an exception if the operation fails, the other returns a
- * special value (either <tt>null</tt> or <tt>false</tt>, depending on
- * the operation).  The latter form of the insert operation is
- * designed specifically for use with capacity-restricted
- * <tt>Deque</tt> implementations; in most implementations, insert
- * operations cannot fail.
- *
- * <p>The twelve methods described above are summarized in the
- * following table:
- *
- * <p>
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
- *  <tr>
- *    <td></td>
- *    <td ALIGN=CENTER COLSPAN = 2> <b>First Element (Head)</b></td>
- *    <td ALIGN=CENTER COLSPAN = 2> <b>Last Element (Tail)</b></td>
- *  </tr>
- *  <tr>
- *    <td></td>
- *    <td ALIGN=CENTER><em>Throws exception</em></td>
- *    <td ALIGN=CENTER><em>Special value</em></td>
- *    <td ALIGN=CENTER><em>Throws exception</em></td>
- *    <td ALIGN=CENTER><em>Special value</em></td>
- *  </tr>
- *  <tr>
- *    <td><b>Insert</b></td>
- *    <td>{@link #addFirst addFirst(e)}</td>
- *    <td>{@link #offerFirst offerFirst(e)}</td>
- *    <td>{@link #addLast addLast(e)}</td>
- *    <td>{@link #offerLast offerLast(e)}</td>
- *  </tr>
- *  <tr>
- *    <td><b>Remove</b></td>
- *    <td>{@link #removeFirst removeFirst()}</td>
- *    <td>{@link #pollFirst pollFirst()}</td>
- *    <td>{@link #removeLast removeLast()}</td>
- *    <td>{@link #pollLast pollLast()}</td>
- *  </tr>
- *  <tr>
- *    <td><b>Examine</b></td>
- *    <td>{@link #getFirst getFirst()}</td>
- *    <td>{@link #peekFirst peekFirst()}</td>
- *    <td>{@link #getLast getLast()}</td>
- *    <td>{@link #peekLast peekLast()}</td>
- *  </tr>
- * </table>
- *
- * <p>This interface extends the {@link Queue} interface.  When a deque is
- * used as a queue, FIFO (First-In-First-Out) behavior results.  Elements are
- * added at the end of the deque and removed from the beginning.  The methods
- * inherited from the <tt>Queue</tt> interface are precisely equivalent to
- * <tt>Deque</tt> methods as indicated in the following table:
- *
- * <p>
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
- *  <tr>
- *    <td ALIGN=CENTER> <b><tt>Queue</tt> Method</b></td>
- *    <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td>
- *  </tr>
- *  <tr>
- *    <td>{@link java.util.Queue#add add(e)}</td>
- *    <td>{@link #addLast addLast(e)}</td>
- *  </tr>
- *  <tr>
- *    <td>{@link java.util.Queue#offer offer(e)}</td>
- *    <td>{@link #offerLast offerLast(e)}</td>
- *  </tr>
- *  <tr>
- *    <td>{@link java.util.Queue#remove remove()}</td>
- *    <td>{@link #removeFirst removeFirst()}</td>
- *  </tr>
- *  <tr>
- *    <td>{@link java.util.Queue#poll poll()}</td>
- *    <td>{@link #pollFirst pollFirst()}</td>
- *  </tr>
- *  <tr>
- *    <td>{@link java.util.Queue#element element()}</td>
- *    <td>{@link #getFirst getFirst()}</td>
- *  </tr>
- *  <tr>
- *    <td>{@link java.util.Queue#peek peek()}</td>
- *    <td>{@link #peek peekFirst()}</td>
- *  </tr>
- * </table>
- *
- * <p>Deques can also be used as LIFO (Last-In-First-Out) stacks.  This
- * interface should be used in preference to the legacy {@link Stack} class.
- * When a deque is used as a stack, elements are pushed and popped from the
- * beginning of the deque.  Stack methods are precisely equivalent to
- * <tt>Deque</tt> methods as indicated in the table below:
- *
- * <p>
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
- *  <tr>
- *    <td ALIGN=CENTER> <b>Stack Method</b></td>
- *    <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td>
- *  </tr>
- *  <tr>
- *    <td>{@link #push push(e)}</td>
- *    <td>{@link #addFirst addFirst(e)}</td>
- *  </tr>
- *  <tr>
- *    <td>{@link #pop pop()}</td>
- *    <td>{@link #removeFirst removeFirst()}</td>
- *  </tr>
- *  <tr>
- *    <td>{@link #peek peek()}</td>
- *    <td>{@link #peekFirst peekFirst()}</td>
- *  </tr>
- * </table>
- *
- * <p>Note that the {@link #peek peek} method works equally well when
- * a deque is used as a queue or a stack; in either case, elements are
- * drawn from the beginning of the deque.
- *
- * <p>This interface provides two methods to remove interior
- * elements, {@link #removeFirstOccurrence removeFirstOccurrence} and
- * {@link #removeLastOccurrence removeLastOccurrence}.
- *
- * <p>Unlike the {@link List} interface, this interface does not
- * provide support for indexed access to elements.
- *
- * <p>While <tt>Deque</tt> implementations are not strictly required
- * to prohibit the insertion of null elements, they are strongly
- * encouraged to do so.  Users of any <tt>Deque</tt> implementations
- * that do allow null elements are strongly encouraged <i>not</i> to
- * take advantage of the ability to insert nulls.  This is so because
- * <tt>null</tt> is used as a special return value by various methods
- * to indicated that the deque is empty.
- *
- * <p><tt>Deque</tt> implementations generally do not define
- * element-based versions of the <tt>equals</tt> and <tt>hashCode</tt>
- * methods, but instead inherit the identity-based versions from class
- * <tt>Object</tt>.
- *
- * @author Doug Lea
- * @author Josh Bloch
- * @since  1.6
- * @param <E> the type of elements held in this collection
- */
-
-public interface Deque<E> extends Queue<E> {
-    /**
-     * Inserts the specified element at the front of this deque if it is
-     * possible to do so immediately without violating capacity restrictions.
-     * When using a capacity-restricted deque, it is generally preferable to
-     * use method {@link #offerFirst}.
-     *
-     * @param e the element to add
-     * @throws IllegalStateException if the element cannot be added at this
-     *         time due to capacity restrictions
-     * @throws ClassCastException if the class of the specified element
-     *         prevents it from being added to this deque
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements
-     * @throws IllegalArgumentException if some property of the specified
-     *         element prevents it from being added to this deque
-     */
-    void addFirst(E e);
-
-    /**
-     * Inserts the specified element at the end of this deque if it is
-     * possible to do so immediately without violating capacity restrictions.
-     * When using a capacity-restricted deque, it is generally preferable to
-     * use method {@link #offerLast}.
-     *
-     * <p>This method is equivalent to {@link #add}.
-     *
-     * @param e the element to add
-     * @throws IllegalStateException if the element cannot be added at this
-     *         time due to capacity restrictions
-     * @throws ClassCastException if the class of the specified element
-     *         prevents it from being added to this deque
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements
-     * @throws IllegalArgumentException if some property of the specified
-     *         element prevents it from being added to this deque
-     */
-    void addLast(E e);
-
-    /**
-     * Inserts the specified element at the front of this deque unless it would
-     * violate capacity restrictions.  When using a capacity-restricted deque,
-     * this method is generally preferable to the {@link #addFirst} method,
-     * which can fail to insert an element only by throwing an exception.
-     *
-     * @param e the element to add
-     * @return <tt>true</tt> if the element was added to this deque, else
-     *         <tt>false</tt>
-     * @throws ClassCastException if the class of the specified element
-     *         prevents it from being added to this deque
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements
-     * @throws IllegalArgumentException if some property of the specified
-     *         element prevents it from being added to this deque
-     */
-    boolean offerFirst(E e);
-
-    /**
-     * Inserts the specified element at the end of this deque unless it would
-     * violate capacity restrictions.  When using a capacity-restricted deque,
-     * this method is generally preferable to the {@link #addLast} method,
-     * which can fail to insert an element only by throwing an exception.
-     *
-     * @param e the element to add
-     * @return <tt>true</tt> if the element was added to this deque, else
-     *         <tt>false</tt>
-     * @throws ClassCastException if the class of the specified element
-     *         prevents it from being added to this deque
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements
-     * @throws IllegalArgumentException if some property of the specified
-     *         element prevents it from being added to this deque
-     */
-    boolean offerLast(E e);
-
-    /**
-     * Retrieves and removes the first element of this deque.  This method
-     * differs from {@link #pollFirst pollFirst} only in that it throws an
-     * exception if this deque is empty.
-     *
-     * @return the head of this deque
-     * @throws NoSuchElementException if this deque is empty
-     */
-    E removeFirst();
-
-    /**
-     * Retrieves and removes the last element of this deque.  This method
-     * differs from {@link #pollLast pollLast} only in that it throws an
-     * exception if this deque is empty.
-     *
-     * @return the tail of this deque
-     * @throws NoSuchElementException if this deque is empty
-     */
-    E removeLast();
-
-    /**
-     * Retrieves and removes the first element of this deque,
-     * or returns <tt>null</tt> if this deque is empty.
-     *
-     * @return the head of this deque, or <tt>null</tt> if this deque is empty
-     */
-    E pollFirst();
-
-    /**
-     * Retrieves and removes the last element of this deque,
-     * or returns <tt>null</tt> if this deque is empty.
-     *
-     * @return the tail of this deque, or <tt>null</tt> if this deque is empty
-     */
-    E pollLast();
-
-    /**
-     * Retrieves, but does not remove, the first element of this deque.
-     *
-     * This method differs from {@link #peekFirst peekFirst} only in that it
-     * throws an exception if this deque is empty.
-     *
-     * @return the head of this deque
-     * @throws NoSuchElementException if this deque is empty
-     */
-    E getFirst();
-
-    /**
-     * Retrieves, but does not remove, the last element of this deque.
-     * This method differs from {@link #peekLast peekLast} only in that it
-     * throws an exception if this deque is empty.
-     *
-     * @return the tail of this deque
-     * @throws NoSuchElementException if this deque is empty
-     */
-    E getLast();
-
-    /**
-     * Retrieves, but does not remove, the first element of this deque,
-     * or returns <tt>null</tt> if this deque is empty.
-     *
-     * @return the head of this deque, or <tt>null</tt> if this deque is empty
-     */
-    E peekFirst();
-
-    /**
-     * Retrieves, but does not remove, the last element of this deque,
-     * or returns <tt>null</tt> if this deque is empty.
-     *
-     * @return the tail of this deque, or <tt>null</tt> if this deque is empty
-     */
-    E peekLast();
-
-    /**
-     * Removes the first occurrence of the specified element from this deque.
-     * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the first element <tt>e</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>
-     * (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
-     * (or equivalently, if this deque changed as a result of the call).
-     *
-     * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if an element was removed as a result of this call
-     * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this deque (optional)
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements (optional)
-     */
-    boolean removeFirstOccurrence(Object o);
-
-    /**
-     * Removes the last occurrence of the specified element from this deque.
-     * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the last element <tt>e</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>
-     * (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
-     * (or equivalently, if this deque changed as a result of the call).
-     *
-     * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if an element was removed as a result of this call
-     * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this deque (optional)
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements (optional)
-     */
-    boolean removeLastOccurrence(Object o);
-
-    // *** Queue methods ***
-
-    /**
-     * Inserts the specified element into the queue represented by this deque
-     * (in other words, at the tail of this deque) if it is possible to do so
-     * immediately without violating capacity restrictions, returning
-     * <tt>true</tt> upon success and throwing an
-     * <tt>IllegalStateException</tt> if no space is currently available.
-     * When using a capacity-restricted deque, it is generally preferable to
-     * use {@link #offer(Object) offer}.
-     *
-     * <p>This method is equivalent to {@link #addLast}.
-     *
-     * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Collection#add})
-     * @throws IllegalStateException if the element cannot be added at this
-     *         time due to capacity restrictions
-     * @throws ClassCastException if the class of the specified element
-     *         prevents it from being added to this deque
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements
-     * @throws IllegalArgumentException if some property of the specified
-     *         element prevents it from being added to this deque
-     */
-    boolean add(E e);
-
-    /**
-     * Inserts the specified element into the queue represented by this deque
-     * (in other words, at the tail of this deque) if it is possible to do so
-     * immediately without violating capacity restrictions, returning
-     * <tt>true</tt> upon success and <tt>false</tt> if no space is currently
-     * available.  When using a capacity-restricted deque, this method is
-     * generally preferable to the {@link #add} method, which can fail to
-     * insert an element only by throwing an exception.
-     *
-     * <p>This method is equivalent to {@link #offerLast}.
-     *
-     * @param e the element to add
-     * @return <tt>true</tt> if the element was added to this deque, else
-     *         <tt>false</tt>
-     * @throws ClassCastException if the class of the specified element
-     *         prevents it from being added to this deque
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements
-     * @throws IllegalArgumentException if some property of the specified
-     *         element prevents it from being added to this deque
-     */
-    boolean offer(E e);
-
-    /**
-     * Retrieves and removes the head of the queue represented by this deque
-     * (in other words, the first element of this deque).
-     * This method differs from {@link #poll poll} only in that it throws an
-     * exception if this deque is empty.
-     *
-     * <p>This method is equivalent to {@link #removeFirst()}.
-     *
-     * @return the head of the queue represented by this deque
-     * @throws NoSuchElementException if this deque is empty
-     */
-    E remove();
-
-    /**
-     * Retrieves and removes the head of the queue represented by this deque
-     * (in other words, the first element of this deque), or returns
-     * <tt>null</tt> if this deque is empty.
-     *
-     * <p>This method is equivalent to {@link #pollFirst()}.
-     *
-     * @return the first element of this deque, or <tt>null</tt> if
-     *         this deque is empty
-     */
-    E poll();
-
-    /**
-     * Retrieves, but does not remove, the head of the queue represented by
-     * this deque (in other words, the first element of this deque).
-     * This method differs from {@link #peek peek} only in that it throws an
-     * exception if this deque is empty.
-     *
-     * <p>This method is equivalent to {@link #getFirst()}.
-     *
-     * @return the head of the queue represented by this deque
-     * @throws NoSuchElementException if this deque is empty
-     */
-    E element();
-
-    /**
-     * Retrieves, but does not remove, the head of the queue represented by
-     * this deque (in other words, the first element of this deque), or
-     * returns <tt>null</tt> if this deque is empty.
-     *
-     * <p>This method is equivalent to {@link #peekFirst()}.
-     *
-     * @return the head of the queue represented by this deque, or
-     *         <tt>null</tt> if this deque is empty
-     */
-    E peek();
-
-
-    // *** Stack methods ***
-
-    /**
-     * Pushes an element onto the stack represented by this deque (in other
-     * words, at the head of this deque) if it is possible to do so
-     * immediately without violating capacity restrictions, returning
-     * <tt>true</tt> upon success and throwing an
-     * <tt>IllegalStateException</tt> if no space is currently available.
-     *
-     * <p>This method is equivalent to {@link #addFirst}.
-     *
-     * @param e the element to push
-     * @throws IllegalStateException if the element cannot be added at this
-     *         time due to capacity restrictions
-     * @throws ClassCastException if the class of the specified element
-     *         prevents it from being added to this deque
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements
-     * @throws IllegalArgumentException if some property of the specified
-     *         element prevents it from being added to this deque
-     */
-    void push(E e);
-
-    /**
-     * Pops an element from the stack represented by this deque.  In other
-     * words, removes and returns the first element of this deque.
-     *
-     * <p>This method is equivalent to {@link #removeFirst()}.
-     *
-     * @return the element at the front of this deque (which is the top
-     *         of the stack represented by this deque)
-     * @throws NoSuchElementException if this deque is empty
-     */
-    E pop();
-
-
-    // *** Collection methods ***
-
-    /**
-     * Removes the first occurrence of the specified element from this deque.
-     * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the first element <tt>e</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>
-     * (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
-     * (or equivalently, if this deque changed as a result of the call).
-     *
-     * <p>This method is equivalent to {@link #removeFirstOccurrence}.
-     *
-     * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if an element was removed as a result of this call
-     * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this deque (optional)
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements (optional)
-     */
-    boolean remove(Object o);
-
-    /**
-     * Returns <tt>true</tt> if this deque contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this deque contains
-     * at least one element <tt>e</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
-     *
-     * @param o element whose presence in this deque is to be tested
-     * @return <tt>true</tt> if this deque contains the specified element
-     * @throws ClassCastException if the type of the specified element
-     *         is incompatible with this deque (optional)
-     * @throws NullPointerException if the specified element is null and this
-     *         deque does not permit null elements (optional)
-     */
-    boolean contains(Object o);
-
-    /**
-     * Returns the number of elements in this deque.
-     *
-     * @return the number of elements in this deque
-     */
-    public int size();
-
-    /**
-     * Returns an iterator over the elements in this deque in proper sequence.
-     * The elements will be returned in order from first (head) to last (tail).
-     *
-     * @return an iterator over the elements in this deque in proper sequence
-     */
-    Iterator<E> iterator();
-
-    /**
-     * Returns an iterator over the elements in this deque in reverse
-     * sequential order.  The elements will be returned in order from
-     * last (tail) to first (head).
-     *
-     * @return an iterator over the elements in this deque in reverse
-     * sequence
-     */
-    Iterator<E> descendingIterator();
-
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/FilePicker.java b/platform/android/src/com/artifex/mupdfdemo/FilePicker.java
deleted file mode 100644
index d1953531..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/FilePicker.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.net.Uri;
-
-public abstract class FilePicker {
-	public interface FilePickerSupport {
-		void performPickFor(FilePicker picker);
-	}
-
-	private final FilePickerSupport support;
-
-	FilePicker(FilePickerSupport _support) {
-		support = _support;
-	}
-
-	void pick() {
-		support.performPickFor(this);
-	}
-
-	abstract void onPick(Uri uri);
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/LinkInfo.java b/platform/android/src/com/artifex/mupdfdemo/LinkInfo.java
deleted file mode 100644
index 5aeaccbe..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/LinkInfo.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.graphics.RectF;
-
-public class LinkInfo {
-	final public RectF rect;
-
-	public LinkInfo(float l, float t, float r, float b) {
-		rect = new RectF(l, t, r, b);
-	}
-
-	public void acceptVisitor(LinkInfoVisitor visitor) {
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/LinkInfoExternal.java b/platform/android/src/com/artifex/mupdfdemo/LinkInfoExternal.java
deleted file mode 100644
index 574b6264..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/LinkInfoExternal.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public class LinkInfoExternal extends LinkInfo {
-	final public String url;
-
-	public LinkInfoExternal(float l, float t, float r, float b, String u) {
-		super(l, t, r, b);
-		url = u;
-	}
-
-	public void acceptVisitor(LinkInfoVisitor visitor) {
-		visitor.visitExternal(this);
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/LinkInfoInternal.java b/platform/android/src/com/artifex/mupdfdemo/LinkInfoInternal.java
deleted file mode 100644
index 761bf87a..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/LinkInfoInternal.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public class LinkInfoInternal extends LinkInfo {
-	final public int pageNumber;
-
-	public LinkInfoInternal(float l, float t, float r, float b, int p) {
-		super(l, t, r, b);
-		pageNumber = p;
-	}
-
-	public void acceptVisitor(LinkInfoVisitor visitor) {
-		visitor.visitInternal(this);
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/LinkInfoRemote.java b/platform/android/src/com/artifex/mupdfdemo/LinkInfoRemote.java
deleted file mode 100644
index 731e6408..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/LinkInfoRemote.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public class LinkInfoRemote extends LinkInfo {
-	final public String fileSpec;
-	final public int pageNumber;
-	final public boolean newWindow;
-
-	public LinkInfoRemote(float l, float t, float r, float b, String f, int p, boolean n) {
-		super(l, t, r, b);
-		fileSpec = f;
-		pageNumber = p;
-		newWindow = n;
-	}
-
-	public void acceptVisitor(LinkInfoVisitor visitor) {
-		visitor.visitRemote(this);
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/LinkInfoVisitor.java b/platform/android/src/com/artifex/mupdfdemo/LinkInfoVisitor.java
deleted file mode 100644
index ecd093e4..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/LinkInfoVisitor.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.artifex.mupdfdemo;
-
-abstract public class LinkInfoVisitor {
-	public abstract void visitInternal(LinkInfoInternal li);
-	public abstract void visitExternal(LinkInfoExternal li);
-	public abstract void visitRemote(LinkInfoRemote li);
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFActivity.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
deleted file mode 100644
index 91b1e8fe..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
+++ /dev/null
@@ -1,1417 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RectShape;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.text.method.PasswordTransformationMethod;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MenuItem.OnMenuItemClickListener;
-import android.view.View;
-import android.view.animation.Animation;
-import android.view.animation.TranslateAnimation;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.PopupMenu;
-import android.widget.RelativeLayout;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.ViewAnimator;
-
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.concurrent.Executor;
-
-class ThreadPerTaskExecutor implements Executor {
-	public void execute(Runnable r) {
-		new Thread(r).start();
-	}
-}
-
-public class MuPDFActivity extends Activity implements FilePicker.FilePickerSupport
-{
-	/* The core rendering instance */
-	enum TopBarMode {Main, Search, Annot, Delete, More, Accept};
-	enum AcceptMode {Highlight, Underline, StrikeOut, Ink, CopyText};
-
-	private final int    OUTLINE_REQUEST=0;
-	private final int    PRINT_REQUEST=1;
-	private final int    FILEPICK_REQUEST=2;
-	private final int    PROOF_REQUEST=3;
-	private MuPDFCore    core;
-	private String       mFileName;
-	private MuPDFReaderView mDocView;
-	private View         mButtonsView;
-	private boolean      mButtonsVisible;
-	private EditText     mPasswordView;
-	private TextView     mFilenameView;
-	private SeekBar      mPageSlider;
-	private int          mPageSliderRes;
-	private TextView     mPageNumberView;
-	private TextView     mInfoView;
-	private ImageButton  mSearchButton;
-	private ImageButton  mReflowButton;
-	private ImageButton  mOutlineButton;
-	private ImageButton	mMoreButton;
-	private TextView     mAnnotTypeText;
-	private ImageButton mAnnotButton;
-	private ViewAnimator mTopBarSwitcher;
-	private ImageButton  mLinkButton;
-	private TopBarMode   mTopBarMode = TopBarMode.Main;
-	private AcceptMode   mAcceptMode;
-	private ImageButton  mSearchBack;
-	private ImageButton  mSearchFwd;
-	private EditText     mSearchText;
-	private SearchTask   mSearchTask;
-	private ImageButton  mProofButton;
-	private ImageButton  mSepsButton;
-	private AlertDialog.Builder mAlertBuilder;
-	private boolean    mLinkHighlight = false;
-	private final Handler mHandler = new Handler();
-	private boolean mAlertsActive= false;
-	private boolean mReflow = false;
-	private AsyncTask<Void,Void,MuPDFAlert> mAlertTask;
-	private AlertDialog mAlertDialog;
-	private FilePicker mFilePicker;
-	private String     mProofFile;
-	private boolean mSepEnabled[][];
-
-	static private AlertDialog.Builder gAlertBuilder;
-	static public AlertDialog.Builder getAlertBuilder() {return gAlertBuilder;}
-
-	public void createAlertWaiter() {
-		mAlertsActive = true;
-		// All mupdf library calls are performed on asynchronous tasks to avoid stalling
-		// the UI. Some calls can lead to javascript-invoked requests to display an
-		// alert dialog and collect a reply from the user. The task has to be blocked
-		// until the user's reply is received. This method creates an asynchronous task,
-		// the purpose of which is to wait of these requests and produce the dialog
-		// in response, while leaving the core blocked. When the dialog receives the
-		// user's response, it is sent to the core via replyToAlert, unblocking it.
-		// Another alert-waiting task is then created to pick up the next alert.
-		if (mAlertTask != null) {
-			mAlertTask.cancel(true);
-			mAlertTask = null;
-		}
-		if (mAlertDialog != null) {
-			mAlertDialog.cancel();
-			mAlertDialog = null;
-		}
-		mAlertTask = new AsyncTask<Void,Void,MuPDFAlert>() {
-
-			@Override
-			protected MuPDFAlert doInBackground(Void... arg0) {
-				if (!mAlertsActive)
-					return null;
-
-				return core.waitForAlert();
-			}
-
-			@Override
-			protected void onPostExecute(final MuPDFAlert result) {
-				// core.waitForAlert may return null when shutting down
-				if (result == null)
-					return;
-				final MuPDFAlert.ButtonPressed pressed[] = new MuPDFAlert.ButtonPressed[3];
-				for(int i = 0; i < 3; i++)
-					pressed[i] = MuPDFAlert.ButtonPressed.None;
-				DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
-					public void onClick(DialogInterface dialog, int which) {
-						mAlertDialog = null;
-						if (mAlertsActive) {
-							int index = 0;
-							switch (which) {
-							case AlertDialog.BUTTON1: index=0; break;
-							case AlertDialog.BUTTON2: index=1; break;
-							case AlertDialog.BUTTON3: index=2; break;
-							}
-							result.buttonPressed = pressed[index];
-							// Send the user's response to the core, so that it can
-							// continue processing.
-							core.replyToAlert(result);
-							// Create another alert-waiter to pick up the next alert.
-							createAlertWaiter();
-						}
-					}
-				};
-				mAlertDialog = mAlertBuilder.create();
-				mAlertDialog.setTitle(result.title);
-				mAlertDialog.setMessage(result.message);
-				switch (result.iconType)
-				{
-				case Error:
-					break;
-				case Warning:
-					break;
-				case Question:
-					break;
-				case Status:
-					break;
-				}
-				switch (result.buttonGroupType)
-				{
-				case OkCancel:
-					mAlertDialog.setButton(AlertDialog.BUTTON2, getString(R.string.cancel), listener);
-					pressed[1] = MuPDFAlert.ButtonPressed.Cancel;
-				case Ok:
-					mAlertDialog.setButton(AlertDialog.BUTTON1, getString(R.string.okay), listener);
-					pressed[0] = MuPDFAlert.ButtonPressed.Ok;
-					break;
-				case YesNoCancel:
-					mAlertDialog.setButton(AlertDialog.BUTTON3, getString(R.string.cancel), listener);
-					pressed[2] = MuPDFAlert.ButtonPressed.Cancel;
-				case YesNo:
-					mAlertDialog.setButton(AlertDialog.BUTTON1, getString(R.string.yes), listener);
-					pressed[0] = MuPDFAlert.ButtonPressed.Yes;
-					mAlertDialog.setButton(AlertDialog.BUTTON2, getString(R.string.no), listener);
-					pressed[1] = MuPDFAlert.ButtonPressed.No;
-					break;
-				}
-				mAlertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-					public void onCancel(DialogInterface dialog) {
-						mAlertDialog = null;
-						if (mAlertsActive) {
-							result.buttonPressed = MuPDFAlert.ButtonPressed.None;
-							core.replyToAlert(result);
-							createAlertWaiter();
-						}
-					}
-				});
-
-				mAlertDialog.show();
-			}
-		};
-
-		mAlertTask.executeOnExecutor(new ThreadPerTaskExecutor());
-	}
-
-	public void destroyAlertWaiter() {
-		mAlertsActive = false;
-		if (mAlertDialog != null) {
-			mAlertDialog.cancel();
-			mAlertDialog = null;
-		}
-		if (mAlertTask != null) {
-			mAlertTask.cancel(true);
-			mAlertTask = null;
-		}
-	}
-
-	private MuPDFCore openFile(String path)
-	{
-		int lastSlashPos = path.lastIndexOf('/');
-		mFileName = new String(lastSlashPos == -1
-					? path
-					: path.substring(lastSlashPos+1));
-		System.out.println("Trying to open " + path);
-		try
-		{
-			core = new MuPDFCore(this, path);
-			// New file: drop the old outline data
-			OutlineActivityData.set(null);
-		}
-		catch (Exception e)
-		{
-			System.out.println(e);
-			return null;
-		}
-		catch (java.lang.OutOfMemoryError e)
-		{
-			//  out of memory is not an Exception, so we catch it separately.
-			System.out.println(e);
-			return null;
-		}
-		return core;
-	}
-
-	private MuPDFCore openBuffer(byte buffer[], String magic)
-	{
-		System.out.println("Trying to open byte buffer");
-		try
-		{
-			core = new MuPDFCore(this, buffer, magic);
-			// New file: drop the old outline data
-			OutlineActivityData.set(null);
-		}
-		catch (Exception e)
-		{
-			System.out.println(e);
-			return null;
-		}
-		return core;
-	}
-
-	//  determine whether the current activity is a proofing activity.
-	public boolean isProofing()
-	{
-		String format = core.fileFormat();
-		return (format.equals("GPROOF"));
-	}
-
-	/** Called when the activity is first created. */
-	@Override
-	public void onCreate(final Bundle savedInstanceState)
-	{
-		super.onCreate(savedInstanceState);
-
-		mAlertBuilder = new AlertDialog.Builder(this);
-		gAlertBuilder = mAlertBuilder;  //  keep a static copy of this that other classes can use
-
-		if (core == null) {
-			core = (MuPDFCore)getLastNonConfigurationInstance();
-
-			if (savedInstanceState != null && savedInstanceState.containsKey("FileName")) {
-				mFileName = savedInstanceState.getString("FileName");
-			}
-		}
-		if (core == null) {
-			Intent intent = getIntent();
-			byte buffer[] = null;
-
-			if (Intent.ACTION_VIEW.equals(intent.getAction())) {
-				Uri uri = intent.getData();
-				System.out.println("URI to open is: " + uri);
-				if (uri.toString().startsWith("content://")) {
-					String reason = null;
-					try {
-						InputStream is = getContentResolver().openInputStream(uri);
-						int len = is.available();
-						buffer = new byte[len];
-						is.read(buffer, 0, len);
-						is.close();
-					}
-					catch (java.lang.OutOfMemoryError e) {
-						System.out.println("Out of memory during buffer reading");
-						reason = e.toString();
-					}
-					catch (Exception e) {
-						System.out.println("Exception reading from stream: " + e);
-
-						// Handle view requests from the Transformer Prime's file manager
-						// Hopefully other file managers will use this same scheme, if not
-						// using explicit paths.
-						// I'm hoping that this case below is no longer needed...but it's
-						// hard to test as the file manager seems to have changed in 4.x.
-						try {
-							Cursor cursor = getContentResolver().query(uri, new String[]{"_data"}, null, null, null);
-							if (cursor.moveToFirst()) {
-								String str = cursor.getString(0);
-								if (str == null) {
-									reason = "Couldn't parse data in intent";
-								}
-								else {
-									uri = Uri.parse(str);
-								}
-							}
-						}
-						catch (Exception e2) {
-							System.out.println("Exception in Transformer Prime file manager code: " + e2);
-							reason = e2.toString();
-						}
-					}
-					if (reason != null) {
-						buffer = null;
-						Resources res = getResources();
-						AlertDialog alert = mAlertBuilder.create();
-						setTitle(String.format(res.getString(R.string.cannot_open_document_Reason), reason));
-						alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.dismiss),
-								new DialogInterface.OnClickListener() {
-									public void onClick(DialogInterface dialog, int which) {
-										finish();
-									}
-								});
-						alert.show();
-						return;
-					}
-				}
-				if (buffer != null) {
-					core = openBuffer(buffer, intent.getType());
-				} else {
-					String path = Uri.decode(uri.getEncodedPath());
-					if (path == null) {
-						path = uri.toString();
-					}
-					core = openFile(path);
-				}
-				SearchTaskResult.set(null);
-			}
-			if (core != null && core.needsPassword()) {
-				requestPassword(savedInstanceState);
-				return;
-			}
-			if (core != null && core.countPages() == 0)
-			{
-				core = null;
-			}
-		}
-		if (core == null)
-		{
-			AlertDialog alert = mAlertBuilder.create();
-			alert.setTitle(R.string.cannot_open_document);
-			alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.dismiss),
-					new DialogInterface.OnClickListener() {
-						public void onClick(DialogInterface dialog, int which) {
-							finish();
-						}
-					});
-			alert.setOnCancelListener(new OnCancelListener() {
-
-				@Override
-				public void onCancel(DialogInterface dialog) {
-					finish();
-				}
-			});
-			alert.show();
-			return;
-		}
-
-		createUI(savedInstanceState);
-
-		//  hide the proof button if this file can't be proofed
-		if (!core.canProof()) {
-			mProofButton.setVisibility(View.INVISIBLE);
-		}
-
-		if (isProofing()) {
-
-			//  start the activity with a new array
-			mSepEnabled = null;
-
-			//  show the separations button
-			mSepsButton.setVisibility(View.VISIBLE);
-
-			//  hide some other buttons
-			mLinkButton.setVisibility(View.INVISIBLE);
-			mReflowButton.setVisibility(View.INVISIBLE);
-			mOutlineButton.setVisibility(View.INVISIBLE);
-			mSearchButton.setVisibility(View.INVISIBLE);
-			mMoreButton.setVisibility(View.INVISIBLE);
-		}
-		else {
-			//  hide the separations button
-			mSepsButton.setVisibility(View.INVISIBLE);
-		}
-
-	}
-
-	public void requestPassword(final Bundle savedInstanceState) {
-		mPasswordView = new EditText(this);
-		mPasswordView.setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
-		mPasswordView.setTransformationMethod(new PasswordTransformationMethod());
-
-		AlertDialog alert = mAlertBuilder.create();
-		alert.setTitle(R.string.enter_password);
-		alert.setView(mPasswordView);
-		alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.okay),
-				new DialogInterface.OnClickListener() {
-					public void onClick(DialogInterface dialog, int which) {
-						if (core.authenticatePassword(mPasswordView.getText().toString())) {
-							createUI(savedInstanceState);
-						} else {
-							requestPassword(savedInstanceState);
-						}
-					}
-				});
-		alert.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.cancel),
-				new DialogInterface.OnClickListener() {
-
-			public void onClick(DialogInterface dialog, int which) {
-				finish();
-			}
-		});
-		alert.show();
-	}
-
-	public void createUI(Bundle savedInstanceState) {
-		if (core == null)
-			return;
-
-		// Now create the UI.
-		// First create the document view
-		mDocView = new MuPDFReaderView(this) {
-			@Override
-			protected void onMoveToChild(int i) {
-				if (core == null)
-					return;
-
-				mPageNumberView.setText(String.format("%d / %d", i + 1,
-						core.countPages()));
-				mPageSlider.setMax((core.countPages() - 1) * mPageSliderRes);
-				mPageSlider.setProgress(i * mPageSliderRes);
-				super.onMoveToChild(i);
-			}
-
-			@Override
-			protected void onTapMainDocArea() {
-				if (!mButtonsVisible) {
-					showButtons();
-				} else {
-					if (mTopBarMode == TopBarMode.Main)
-						hideButtons();
-				}
-			}
-
-			@Override
-			protected void onDocMotion() {
-				hideButtons();
-			}
-
-			@Override
-			protected void onHit(Hit item) {
-				switch (mTopBarMode) {
-				case Annot:
-					if (item == Hit.Annotation) {
-						showButtons();
-						mTopBarMode = TopBarMode.Delete;
-						mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-					}
-					break;
-				case Delete:
-					mTopBarMode = TopBarMode.Annot;
-					mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-				// fall through
-				default:
-					// Not in annotation editing mode, but the pageview will
-					// still select and highlight hit annotations, so
-					// deselect just in case.
-					MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
-					if (pageView != null)
-						pageView.deselectAnnotation();
-					break;
-				}
-			}
-		};
-		mDocView.setAdapter(new MuPDFPageAdapter(this, this, core));
-
-		mSearchTask = new SearchTask(this, core) {
-			@Override
-			protected void onTextFound(SearchTaskResult result) {
-				SearchTaskResult.set(result);
-				// Ask the ReaderView to move to the resulting page
-				mDocView.setDisplayedViewIndex(result.pageNumber);
-				// Make the ReaderView act on the change to SearchTaskResult
-				// via overridden onChildSetup method.
-				mDocView.resetupChildren();
-			}
-		};
-
-		// Make the buttons overlay, and store all its
-		// controls in variables
-		makeButtonsView();
-
-		// Set up the page slider
-		int smax = Math.max(core.countPages()-1,1);
-		mPageSliderRes = ((10 + smax - 1)/smax) * 2;
-
-		// Set the file-name text
-		mFilenameView.setText(mFileName);
-
-		// Activate the seekbar
-		mPageSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-			public void onStopTrackingTouch(SeekBar seekBar) {
-				mDocView.setDisplayedViewIndex((seekBar.getProgress()+mPageSliderRes/2)/mPageSliderRes);
-			}
-
-			public void onStartTrackingTouch(SeekBar seekBar) {}
-
-			public void onProgressChanged(SeekBar seekBar, int progress,
-					boolean fromUser) {
-				updatePageNumView((progress+mPageSliderRes/2)/mPageSliderRes);
-			}
-		});
-
-		// Activate the search-preparing button
-		mSearchButton.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				searchModeOn();
-			}
-		});
-
-		// Activate the reflow button
-		mReflowButton.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				toggleReflow();
-			}
-		});
-
-		if (core.fileFormat().startsWith("PDF") && core.isUnencryptedPDF() && !core.wasOpenedFromBuffer())
-		{
-			mAnnotButton.setOnClickListener(new View.OnClickListener() {
-				public void onClick(View v) {
-					mTopBarMode = TopBarMode.Annot;
-					mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-				}
-			});
-		}
-		else
-		{
-			mAnnotButton.setVisibility(View.GONE);
-		}
-
-		// Search invoking buttons are disabled while there is no text specified
-		mSearchBack.setEnabled(false);
-		mSearchFwd.setEnabled(false);
-		mSearchBack.setColorFilter(Color.argb(255, 128, 128, 128));
-		mSearchFwd.setColorFilter(Color.argb(255, 128, 128, 128));
-
-		// React to interaction with the text widget
-		mSearchText.addTextChangedListener(new TextWatcher() {
-
-			public void afterTextChanged(Editable s) {
-				boolean haveText = s.toString().length() > 0;
-				setButtonEnabled(mSearchBack, haveText);
-				setButtonEnabled(mSearchFwd, haveText);
-
-				// Remove any previous search results
-				if (SearchTaskResult.get() != null && !mSearchText.getText().toString().equals(SearchTaskResult.get().txt)) {
-					SearchTaskResult.set(null);
-					mDocView.resetupChildren();
-				}
-			}
-			public void beforeTextChanged(CharSequence s, int start, int count,
-					int after) {}
-			public void onTextChanged(CharSequence s, int start, int before,
-					int count) {}
-		});
-
-		//React to Done button on keyboard
-		mSearchText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-			public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-				if (actionId == EditorInfo.IME_ACTION_DONE)
-					search(1);
-				return false;
-			}
-		});
-
-		mSearchText.setOnKeyListener(new View.OnKeyListener() {
-			public boolean onKey(View v, int keyCode, KeyEvent event) {
-				if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER)
-					search(1);
-				return false;
-			}
-		});
-
-		// Activate search invoking buttons
-		mSearchBack.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				search(-1);
-			}
-		});
-		mSearchFwd.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				search(1);
-			}
-		});
-
-		mLinkButton.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				setLinkHighlight(!mLinkHighlight);
-			}
-		});
-
-		if (core.hasOutline()) {
-			mOutlineButton.setOnClickListener(new View.OnClickListener() {
-				public void onClick(View v) {
-					OutlineItem outline[] = core.getOutline();
-					if (outline != null) {
-						OutlineActivityData.get().items = outline;
-						Intent intent = new Intent(MuPDFActivity.this, OutlineActivity.class);
-						startActivityForResult(intent, OUTLINE_REQUEST);
-					}
-				}
-			});
-		} else {
-			mOutlineButton.setVisibility(View.GONE);
-		}
-
-		// Reenstate last state if it was recorded
-		SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
-		mDocView.setDisplayedViewIndex(prefs.getInt("page"+mFileName, 0));
-
-		if (savedInstanceState == null || !savedInstanceState.getBoolean("ButtonsHidden", false))
-			showButtons();
-
-		if(savedInstanceState != null && savedInstanceState.getBoolean("SearchMode", false))
-			searchModeOn();
-
-		if(savedInstanceState != null && savedInstanceState.getBoolean("ReflowMode", false))
-			reflowModeSet(true);
-
-		// Stick the document view and the buttons overlay into a parent view
-		RelativeLayout layout = new RelativeLayout(this);
-		layout.addView(mDocView);
-		layout.addView(mButtonsView);
-		setContentView(layout);
-
-		if (isProofing()) {
-			//  go to the current page
-			int currentPage = getIntent().getIntExtra("startingPage", 0);
-			mDocView.setDisplayedViewIndex(currentPage);
-		}
-
-	}
-
-	@Override
-	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-		switch (requestCode) {
-		case OUTLINE_REQUEST:
-			if (resultCode >= 0)
-				mDocView.setDisplayedViewIndex(resultCode);
-			break;
-		case PRINT_REQUEST:
-			if (resultCode == RESULT_CANCELED)
-				showInfo(getString(R.string.print_failed));
-			break;
-		case FILEPICK_REQUEST:
-			if (mFilePicker != null && resultCode == RESULT_OK)
-				mFilePicker.onPick(data.getData());
-		case PROOF_REQUEST:
-			//  we're returning from a proofing activity
-
-			if (mProofFile != null)
-			{
-				core.endProof(mProofFile);
-				mProofFile = null;
-			}
-
-			//  return the top bar to default
-			mTopBarMode = TopBarMode.Main;
-			mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-		}
-
-		super.onActivityResult(requestCode, resultCode, data);
-	}
-
-	public Object onRetainNonConfigurationInstance()
-	{
-		MuPDFCore mycore = core;
-		core = null;
-		return mycore;
-	}
-
-	private void reflowModeSet(boolean reflow)
-	{
-		mReflow = reflow;
-		mDocView.setAdapter(mReflow ? new MuPDFReflowAdapter(this, core) : new MuPDFPageAdapter(this, this, core));
-		mReflowButton.setColorFilter(mReflow ? Color.argb(0xFF, 172, 114, 37) : Color.argb(0xFF, 255, 255, 255));
-		setButtonEnabled(mAnnotButton, !reflow);
-		setButtonEnabled(mSearchButton, !reflow);
-		if (reflow) setLinkHighlight(false);
-		setButtonEnabled(mLinkButton, !reflow);
-		setButtonEnabled(mMoreButton, !reflow);
-		mDocView.refresh(mReflow);
-	}
-
-	private void toggleReflow() {
-		reflowModeSet(!mReflow);
-		showInfo(mReflow ? getString(R.string.entering_reflow_mode) : getString(R.string.leaving_reflow_mode));
-	}
-
-	@Override
-	protected void onSaveInstanceState(Bundle outState) {
-		super.onSaveInstanceState(outState);
-
-		if (mFileName != null && mDocView != null) {
-			outState.putString("FileName", mFileName);
-
-			// Store current page in the prefs against the file name,
-			// so that we can pick it up each time the file is loaded
-			// Other info is needed only for screen-orientation change,
-			// so it can go in the bundle
-			SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
-			SharedPreferences.Editor edit = prefs.edit();
-			edit.putInt("page"+mFileName, mDocView.getDisplayedViewIndex());
-			edit.commit();
-		}
-
-		if (!mButtonsVisible)
-			outState.putBoolean("ButtonsHidden", true);
-
-		if (mTopBarMode == TopBarMode.Search)
-			outState.putBoolean("SearchMode", true);
-
-		if (mReflow)
-			outState.putBoolean("ReflowMode", true);
-	}
-
-	@Override
-	protected void onPause() {
-		super.onPause();
-
-		if (mSearchTask != null)
-			mSearchTask.stop();
-
-		if (mFileName != null && mDocView != null) {
-			SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
-			SharedPreferences.Editor edit = prefs.edit();
-			edit.putInt("page"+mFileName, mDocView.getDisplayedViewIndex());
-			edit.commit();
-		}
-	}
-
-	public void onDestroy()
-	{
-		if (mDocView != null) {
-			mDocView.applyToChildren(new ReaderView.ViewMapper() {
-				void applyToView(View view) {
-					((MuPDFView)view).releaseBitmaps();
-				}
-			});
-		}
-		if (core != null)
-			core.onDestroy();
-		if (mAlertTask != null) {
-			mAlertTask.cancel(true);
-			mAlertTask = null;
-		}
-		core = null;
-		super.onDestroy();
-	}
-
-	private void setButtonEnabled(ImageButton button, boolean enabled) {
-		button.setEnabled(enabled);
-		button.setColorFilter(enabled ? Color.argb(255, 255, 255, 255) : Color.argb(255, 128, 128, 128));
-	}
-
-	private void setLinkHighlight(boolean highlight) {
-		mLinkHighlight = highlight;
-		// LINK_COLOR tint
-		mLinkButton.setColorFilter(highlight ? Color.argb(0xFF, 172, 114, 37) : Color.argb(0xFF, 255, 255, 255));
-		// Inform pages of the change.
-		mDocView.setLinksEnabled(highlight);
-	}
-
-	private void showButtons() {
-		if (core == null)
-			return;
-		if (!mButtonsVisible) {
-			mButtonsVisible = true;
-			// Update page number text and slider
-			int index = mDocView.getDisplayedViewIndex();
-			updatePageNumView(index);
-			mPageSlider.setMax((core.countPages()-1)*mPageSliderRes);
-			mPageSlider.setProgress(index * mPageSliderRes);
-			if (mTopBarMode == TopBarMode.Search) {
-				mSearchText.requestFocus();
-				showKeyboard();
-			}
-
-			Animation anim = new TranslateAnimation(0, 0, -mTopBarSwitcher.getHeight(), 0);
-			anim.setDuration(200);
-			anim.setAnimationListener(new Animation.AnimationListener() {
-				public void onAnimationStart(Animation animation) {
-					mTopBarSwitcher.setVisibility(View.VISIBLE);
-				}
-				public void onAnimationRepeat(Animation animation) {}
-				public void onAnimationEnd(Animation animation) {}
-			});
-			mTopBarSwitcher.startAnimation(anim);
-
-			anim = new TranslateAnimation(0, 0, mPageSlider.getHeight(), 0);
-			anim.setDuration(200);
-			anim.setAnimationListener(new Animation.AnimationListener() {
-				public void onAnimationStart(Animation animation) {
-					mPageSlider.setVisibility(View.VISIBLE);
-				}
-				public void onAnimationRepeat(Animation animation) {}
-				public void onAnimationEnd(Animation animation) {
-					mPageNumberView.setVisibility(View.VISIBLE);
-				}
-			});
-			mPageSlider.startAnimation(anim);
-		}
-	}
-
-	private void hideButtons() {
-		if (mButtonsVisible) {
-			mButtonsVisible = false;
-			hideKeyboard();
-
-			Animation anim = new TranslateAnimation(0, 0, 0, -mTopBarSwitcher.getHeight());
-			anim.setDuration(200);
-			anim.setAnimationListener(new Animation.AnimationListener() {
-				public void onAnimationStart(Animation animation) {}
-				public void onAnimationRepeat(Animation animation) {}
-				public void onAnimationEnd(Animation animation) {
-					mTopBarSwitcher.setVisibility(View.INVISIBLE);
-				}
-			});
-			mTopBarSwitcher.startAnimation(anim);
-
-			anim = new TranslateAnimation(0, 0, 0, mPageSlider.getHeight());
-			anim.setDuration(200);
-			anim.setAnimationListener(new Animation.AnimationListener() {
-				public void onAnimationStart(Animation animation) {
-					mPageNumberView.setVisibility(View.INVISIBLE);
-				}
-				public void onAnimationRepeat(Animation animation) {}
-				public void onAnimationEnd(Animation animation) {
-					mPageSlider.setVisibility(View.INVISIBLE);
-				}
-			});
-			mPageSlider.startAnimation(anim);
-		}
-	}
-
-	private void searchModeOn() {
-		if (mTopBarMode != TopBarMode.Search) {
-			mTopBarMode = TopBarMode.Search;
-			//Focus on EditTextWidget
-			mSearchText.requestFocus();
-			showKeyboard();
-			mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-		}
-	}
-
-	private void searchModeOff() {
-		if (mTopBarMode == TopBarMode.Search) {
-			mTopBarMode = TopBarMode.Main;
-			hideKeyboard();
-			mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-			SearchTaskResult.set(null);
-			// Make the ReaderView act on the change to mSearchTaskResult
-			// via overridden onChildSetup method.
-			mDocView.resetupChildren();
-		}
-	}
-
-	private void updatePageNumView(int index) {
-		if (core == null)
-			return;
-		mPageNumberView.setText(String.format("%d / %d", index + 1, core.countPages()));
-	}
-
-	private void printDoc() {
-		if (!core.fileFormat().startsWith("PDF")) {
-			showInfo(getString(R.string.format_currently_not_supported));
-			return;
-		}
-
-		Intent myIntent = getIntent();
-		Uri docUri = myIntent != null ? myIntent.getData() : null;
-
-		if (docUri == null) {
-			showInfo(getString(R.string.print_failed));
-		}
-
-		if (docUri.getScheme() == null)
-			docUri = Uri.parse("file://"+docUri.toString());
-
-		Intent printIntent = new Intent(this, PrintDialogActivity.class);
-		printIntent.setDataAndType(docUri, "aplication/pdf");
-		printIntent.putExtra("title", mFileName);
-		startActivityForResult(printIntent, PRINT_REQUEST);
-	}
-
-	private void showInfo(String message) {
-		mInfoView.setText(message);
-
-		int currentApiVersion = android.os.Build.VERSION.SDK_INT;
-		if (currentApiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) {
-			SafeAnimatorInflater safe = new SafeAnimatorInflater((Activity)this, R.animator.info, (View)mInfoView);
-		} else {
-			mInfoView.setVisibility(View.VISIBLE);
-			mHandler.postDelayed(new Runnable() {
-				public void run() {
-					mInfoView.setVisibility(View.INVISIBLE);
-				}
-			}, 500);
-		}
-	}
-
-	private void makeButtonsView() {
-		mButtonsView = getLayoutInflater().inflate(R.layout.buttons,null);
-		mFilenameView = (TextView)mButtonsView.findViewById(R.id.docNameText);
-		mPageSlider = (SeekBar)mButtonsView.findViewById(R.id.pageSlider);
-		mPageNumberView = (TextView)mButtonsView.findViewById(R.id.pageNumber);
-		mInfoView = (TextView)mButtonsView.findViewById(R.id.info);
-		mSearchButton = (ImageButton)mButtonsView.findViewById(R.id.searchButton);
-		mReflowButton = (ImageButton)mButtonsView.findViewById(R.id.reflowButton);
-		mOutlineButton = (ImageButton)mButtonsView.findViewById(R.id.outlineButton);
-		mAnnotButton = (ImageButton)mButtonsView.findViewById(R.id.editAnnotButton);
-		mAnnotTypeText = (TextView)mButtonsView.findViewById(R.id.annotType);
-		mTopBarSwitcher = (ViewAnimator)mButtonsView.findViewById(R.id.switcher);
-		mSearchBack = (ImageButton)mButtonsView.findViewById(R.id.searchBack);
-		mSearchFwd = (ImageButton)mButtonsView.findViewById(R.id.searchForward);
-		mSearchText = (EditText)mButtonsView.findViewById(R.id.searchText);
-		mLinkButton = (ImageButton)mButtonsView.findViewById(R.id.linkButton);
-		mMoreButton = (ImageButton)mButtonsView.findViewById(R.id.moreButton);
-		mProofButton = (ImageButton)mButtonsView.findViewById(R.id.proofButton);
-		mSepsButton = (ImageButton)mButtonsView.findViewById(R.id.sepsButton);
-		mTopBarSwitcher.setVisibility(View.INVISIBLE);
-		mPageNumberView.setVisibility(View.INVISIBLE);
-		mInfoView.setVisibility(View.INVISIBLE);
-
-		mPageSlider.setVisibility(View.INVISIBLE);
-		if (!core.gprfSupported()) {
-			mProofButton.setVisibility(View.INVISIBLE);
-		}
-		mSepsButton.setVisibility(View.INVISIBLE);
-	}
-
-	public void OnMoreButtonClick(View v) {
-		mTopBarMode = TopBarMode.More;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-	}
-
-	public void OnCancelMoreButtonClick(View v) {
-		mTopBarMode = TopBarMode.Main;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-	}
-
-	public void OnPrintButtonClick(View v) {
-		printDoc();
-	}
-
-	//  start a proof activity with the given resolution.
-	public void proofWithResolution (int resolution)
-	{
-		mProofFile = core.startProof(resolution);
-		Uri uri = Uri.parse("file://"+mProofFile);
-		Intent intent = new Intent(this, MuPDFActivity.class);
-		intent.setAction(Intent.ACTION_VIEW);
-		intent.setData(uri);
-		// add the current page so it can be found when the activity is running
-		intent.putExtra("startingPage", mDocView.getDisplayedViewIndex());
-		startActivityForResult(intent, PROOF_REQUEST);
-	}
-
-	public void OnProofButtonClick(final View v)
-	{
-		//  set up the menu or resolutions.
-		final PopupMenu popup = new PopupMenu(this, v);
-		popup.getMenu().add(0, 1,    0, "Select a resolution:");
-		popup.getMenu().add(0, 72,   0, "72");
-		popup.getMenu().add(0, 96,   0, "96");
-		popup.getMenu().add(0, 150,  0, "150");
-		popup.getMenu().add(0, 300,  0, "300");
-		popup.getMenu().add(0, 600,  0, "600");
-		popup.getMenu().add(0, 1200, 0, "1200");
-		popup.getMenu().add(0, 2400, 0, "2400");
-
-		//  prevent the first item from being dismissed.
-		//  is there not a better way to do this?  It requires minimum API 14
-		MenuItem item = popup.getMenu().getItem(0);
-		item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
-		item.setActionView(new View(v.getContext()));
-		item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
-			@Override
-			public boolean onMenuItemActionExpand(MenuItem item) {
-				return false;
-			}
-
-			@Override
-			public boolean onMenuItemActionCollapse(MenuItem item) {
-				return false;
-			}
-		});
-
-		popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
-			@Override
-			public boolean onMenuItemClick(MenuItem item) {
-				int id = item.getItemId();
-				if (id != 1) {
-					//  it's a resolution.  The id is also the resolution value
-					proofWithResolution(id);
-					return true;
-				}
-				return false;
-			}
-		});
-
-		popup.show();
-	}
-
-	public void OnSepsButtonClick(final View v)
-	{
-		if (isProofing()) {
-
-			//  get the current page
-			final int currentPage = mDocView.getDisplayedViewIndex();
-
-			//  buid a popup menu based on the given separations
-			final PopupMenu menu = new PopupMenu(this, v);
-
-			//  This makes the popup menu display icons, which by default it does not do.
-			//  I worry that this relies on the internals of PopupMenu, which could change.
-			try {
-				Field[] fields = menu.getClass().getDeclaredFields();
-				for (Field field : fields) {
-					if ("mPopup".equals(field.getName())) {
-						field.setAccessible(true);
-						Object menuPopupHelper = field.get(menu);
-						Class<?> classPopupHelper = Class.forName(menuPopupHelper
-								.getClass().getName());
-						Method setForceIcons = classPopupHelper.getMethod(
-								"setForceShowIcon", boolean.class);
-						setForceIcons.invoke(menuPopupHelper, true);
-						break;
-					}
-				}
-			} catch (Exception e) {
-				e.printStackTrace();
-			}
-
-			//  get the maximum number of seps on any page.
-			//  We use this to dimension an array further down
-			int maxSeps = 0;
-			int numPages = core.countPages();
-			for (int page=0; page<numPages; page++) {
-				int numSeps = core.getNumSepsOnPage(page);
-				if (numSeps>maxSeps)
-					maxSeps = numSeps;
-			}
-
-			//  if this is the first time, create the "enabled" array
-			if (mSepEnabled==null) {
-				mSepEnabled = new boolean[numPages][maxSeps];
-				for (int page=0; page<numPages; page++) {
-					for (int i = 0; i < maxSeps; i++)
-						mSepEnabled[page][i] = true;
-				}
-			}
-
-			//  count the seps on this page
-			int numSeps = core.getNumSepsOnPage(currentPage);
-
-			//  for each sep,
-			for (int i = 0; i < numSeps; i++) {
-
-//				//  Robin use this to skip separations
-//				if (i==12)
-//					break;
-
-				//  get the name
-				Separation sep = core.getSep(currentPage,i);
-				String name = sep.name;
-
-				//  make a checkable menu item with that name
-				//  and the separation index as the id
-				MenuItem item = menu.getMenu().add(0, i, 0, name+"    ");
-				item.setCheckable(true);
-
-				//  set an icon that's the right color
-				int iconSize = 48;
-				int alpha = (sep.rgba >> 24) & 0xFF;
-				int red   = (sep.rgba >> 16) & 0xFF;
-				int green = (sep.rgba >> 8 ) & 0xFF;
-				int blue  = (sep.rgba >> 0 ) & 0xFF;
-				int color = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
-
-				ShapeDrawable swatch = new ShapeDrawable (new RectShape());
-				swatch.setIntrinsicHeight(iconSize);
-				swatch.setIntrinsicWidth(iconSize);
-				swatch.setBounds(new Rect(0, 0, iconSize, iconSize));
-				swatch.getPaint().setColor(color);
-				item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
-				item.setIcon(swatch);
-
-				//  check it (or not)
-				item.setChecked(mSepEnabled[currentPage][i]);
-
-				//  establishing a menu item listener
-				item.setOnMenuItemClickListener(new OnMenuItemClickListener() {
-					@Override
-					public boolean onMenuItemClick(MenuItem item) {
-						//  someone tapped a menu item.  get the ID
-						int sep = item.getItemId();
-
-						//  toggle the sep
-						mSepEnabled[currentPage][sep] = !mSepEnabled[currentPage][sep];
-						item.setChecked(mSepEnabled[currentPage][sep]);
-						core.controlSepOnPage(currentPage, sep, !mSepEnabled[currentPage][sep]);
-
-						//  prevent the menu from being dismissed by these items
-						item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
-						item.setActionView(new View(v.getContext()));
-						item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
-							@Override
-							public boolean onMenuItemActionExpand(MenuItem item) {
-								return false;
-							}
-
-							@Override
-							public boolean onMenuItemActionCollapse(MenuItem item) {
-								return false;
-							}
-						});
-						return false;
-					}
-				});
-
-				//  tell core to enable or disable each sep as appropriate
-				//  but don't refresh the page yet.
-				core.controlSepOnPage(currentPage, i, !mSepEnabled[currentPage][i]);
-			}
-
-			//  add one for done
-			MenuItem itemDone = menu.getMenu().add(0, 0, 0, "Done");
-			itemDone.setOnMenuItemClickListener(new OnMenuItemClickListener() {
-				@Override
-				public boolean onMenuItemClick(MenuItem item) {
-					//  refresh the view
-					mDocView.refresh(false);
-					return true;
-				}
-			});
-
-			//  show the menu
-			menu.show();
-		}
-
-	}
-
-	public void OnCopyTextButtonClick(View v) {
-		mTopBarMode = TopBarMode.Accept;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-		mAcceptMode = AcceptMode.CopyText;
-		mDocView.setMode(MuPDFReaderView.Mode.Selecting);
-		mAnnotTypeText.setText(getString(R.string.copy_text));
-		showInfo(getString(R.string.select_text));
-	}
-
-	public void OnEditAnnotButtonClick(View v) {
-		mTopBarMode = TopBarMode.Annot;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-	}
-
-	public void OnCancelAnnotButtonClick(View v) {
-		mTopBarMode = TopBarMode.More;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-	}
-
-	public void OnHighlightButtonClick(View v) {
-		mTopBarMode = TopBarMode.Accept;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-		mAcceptMode = AcceptMode.Highlight;
-		mDocView.setMode(MuPDFReaderView.Mode.Selecting);
-		mAnnotTypeText.setText(R.string.highlight);
-		showInfo(getString(R.string.select_text));
-	}
-
-	public void OnUnderlineButtonClick(View v) {
-		mTopBarMode = TopBarMode.Accept;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-		mAcceptMode = AcceptMode.Underline;
-		mDocView.setMode(MuPDFReaderView.Mode.Selecting);
-		mAnnotTypeText.setText(R.string.underline);
-		showInfo(getString(R.string.select_text));
-	}
-
-	public void OnStrikeOutButtonClick(View v) {
-		mTopBarMode = TopBarMode.Accept;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-		mAcceptMode = AcceptMode.StrikeOut;
-		mDocView.setMode(MuPDFReaderView.Mode.Selecting);
-		mAnnotTypeText.setText(R.string.strike_out);
-		showInfo(getString(R.string.select_text));
-	}
-
-	public void OnInkButtonClick(View v) {
-		mTopBarMode = TopBarMode.Accept;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-		mAcceptMode = AcceptMode.Ink;
-		mDocView.setMode(MuPDFReaderView.Mode.Drawing);
-		mAnnotTypeText.setText(R.string.ink);
-		showInfo(getString(R.string.draw_annotation));
-	}
-
-	public void OnCancelAcceptButtonClick(View v) {
-		MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
-		if (pageView != null) {
-			pageView.deselectText();
-			pageView.cancelDraw();
-		}
-		mDocView.setMode(MuPDFReaderView.Mode.Viewing);
-		switch (mAcceptMode) {
-		case CopyText:
-			mTopBarMode = TopBarMode.More;
-			break;
-		default:
-			mTopBarMode = TopBarMode.Annot;
-			break;
-		}
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-	}
-
-	public void OnAcceptButtonClick(View v) {
-		MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
-		boolean success = false;
-		switch (mAcceptMode) {
-		case CopyText:
-			if (pageView != null)
-				success = pageView.copySelection();
-			mTopBarMode = TopBarMode.More;
-			showInfo(success?getString(R.string.copied_to_clipboard):getString(R.string.no_text_selected));
-			break;
-
-		case Highlight:
-			if (pageView != null)
-				success = pageView.markupSelection(Annotation.Type.HIGHLIGHT);
-			mTopBarMode = TopBarMode.Annot;
-			if (!success)
-				showInfo(getString(R.string.no_text_selected));
-			break;
-
-		case Underline:
-			if (pageView != null)
-				success = pageView.markupSelection(Annotation.Type.UNDERLINE);
-			mTopBarMode = TopBarMode.Annot;
-			if (!success)
-				showInfo(getString(R.string.no_text_selected));
-			break;
-
-		case StrikeOut:
-			if (pageView != null)
-				success = pageView.markupSelection(Annotation.Type.STRIKEOUT);
-			mTopBarMode = TopBarMode.Annot;
-			if (!success)
-				showInfo(getString(R.string.no_text_selected));
-			break;
-
-		case Ink:
-			if (pageView != null)
-				success = pageView.saveDraw();
-			mTopBarMode = TopBarMode.Annot;
-			if (!success)
-				showInfo(getString(R.string.nothing_to_save));
-			break;
-		}
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-		mDocView.setMode(MuPDFReaderView.Mode.Viewing);
-	}
-
-	public void OnCancelSearchButtonClick(View v) {
-		searchModeOff();
-	}
-
-	public void OnDeleteButtonClick(View v) {
-		MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
-		if (pageView != null)
-			pageView.deleteSelectedAnnotation();
-		mTopBarMode = TopBarMode.Annot;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-	}
-
-	public void OnCancelDeleteButtonClick(View v) {
-		MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
-		if (pageView != null)
-			pageView.deselectAnnotation();
-		mTopBarMode = TopBarMode.Annot;
-		mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
-	}
-
-	private void showKeyboard() {
-		InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
-		if (imm != null)
-			imm.showSoftInput(mSearchText, 0);
-	}
-
-	private void hideKeyboard() {
-		InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
-		if (imm != null)
-			imm.hideSoftInputFromWindow(mSearchText.getWindowToken(), 0);
-	}
-
-	private void search(int direction) {
-		hideKeyboard();
-		int displayPage = mDocView.getDisplayedViewIndex();
-		SearchTaskResult r = SearchTaskResult.get();
-		int searchPage = r != null ? r.pageNumber : -1;
-		mSearchTask.go(mSearchText.getText().toString(), direction, displayPage, searchPage);
-	}
-
-	@Override
-	public boolean onSearchRequested() {
-		if (mButtonsVisible && mTopBarMode == TopBarMode.Search) {
-			hideButtons();
-		} else {
-			showButtons();
-			searchModeOn();
-		}
-		return super.onSearchRequested();
-	}
-
-	@Override
-	public boolean onPrepareOptionsMenu(Menu menu) {
-		if (mButtonsVisible && mTopBarMode != TopBarMode.Search) {
-			hideButtons();
-		} else {
-			showButtons();
-			searchModeOff();
-		}
-		return super.onPrepareOptionsMenu(menu);
-	}
-
-	@Override
-	protected void onStart() {
-		if (core != null)
-		{
-			core.startAlerts();
-			createAlertWaiter();
-		}
-
-		super.onStart();
-	}
-
-	@Override
-	protected void onStop() {
-		if (core != null)
-		{
-			destroyAlertWaiter();
-			core.stopAlerts();
-		}
-
-		super.onStop();
-	}
-
-	@Override
-	public void onBackPressed() {
-		if (core != null && core.hasChanges()) {
-			DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
-				public void onClick(DialogInterface dialog, int which) {
-					if (which == AlertDialog.BUTTON_POSITIVE)
-						core.save();
-
-					finish();
-				}
-			};
-			AlertDialog alert = mAlertBuilder.create();
-			alert.setTitle("MuPDF");
-			alert.setMessage(getString(R.string.document_has_changes_save_them_));
-			alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.yes), listener);
-			alert.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.no), listener);
-			alert.show();
-		} else {
-			super.onBackPressed();
-		}
-	}
-
-	@Override
-	public void performPickFor(FilePicker picker) {
-		mFilePicker = picker;
-		Intent intent = new Intent(this, ChoosePDFActivity.class);
-		intent.setAction(ChoosePDFActivity.PICK_KEY_FILE);
-		startActivityForResult(intent, FILEPICK_REQUEST);
-	}
-
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFAlert.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFAlert.java
deleted file mode 100644
index 76ed3a65..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFAlert.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public class MuPDFAlert {
-	public enum IconType {Error,Warning,Question,Status};
-	public enum ButtonPressed {None,Ok,Cancel,No,Yes};
-	public enum ButtonGroupType {Ok,OkCancel,YesNo,YesNoCancel};
-
-	public final String message;
-	public final IconType iconType;
-	public final ButtonGroupType buttonGroupType;
-	public final String title;
-	public ButtonPressed buttonPressed;
-
-	MuPDFAlert(String aMessage, IconType aIconType, ButtonGroupType aButtonGroupType, String aTitle, ButtonPressed aButtonPressed) {
-		message = aMessage;
-		iconType = aIconType;
-		buttonGroupType = aButtonGroupType;
-		title = aTitle;
-		buttonPressed = aButtonPressed;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFAlertInternal.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFAlertInternal.java
deleted file mode 100644
index 5d65768f..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFAlertInternal.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.artifex.mupdfdemo;
-
-// Version of MuPDFAlert without enums to simplify JNI
-public class MuPDFAlertInternal {
-	public final String message;
-	public final int iconType;
-	public final int buttonGroupType;
-	public final String title;
-	public int buttonPressed;
-
-	MuPDFAlertInternal(String aMessage, int aIconType, int aButtonGroupType, String aTitle, int aButtonPressed) {
-		message = aMessage;
-		iconType = aIconType;
-		buttonGroupType = aButtonGroupType;
-		title = aTitle;
-		buttonPressed = aButtonPressed;
-	}
-
-	MuPDFAlertInternal(MuPDFAlert alert) {
-		message = alert.message;
-		iconType = alert.iconType.ordinal();
-		buttonGroupType = alert.buttonGroupType.ordinal();
-		title = alert.message;
-		buttonPressed = alert.buttonPressed.ordinal();
-	}
-
-	MuPDFAlert toAlert() {
-		return new MuPDFAlert(message, MuPDFAlert.IconType.values()[iconType], MuPDFAlert.ButtonGroupType.values()[buttonGroupType], title, MuPDFAlert.ButtonPressed.values()[buttonPressed]);
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFCancellableTaskDefinition.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFCancellableTaskDefinition.java
deleted file mode 100644
index b95d8e93..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFCancellableTaskDefinition.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public abstract class MuPDFCancellableTaskDefinition<Params, Result> implements CancellableTaskDefinition<Params, Result>
-{
-	private MuPDFCore.Cookie cookie;
-
-	public MuPDFCancellableTaskDefinition(MuPDFCore core)
-	{
-		this.cookie = core.new Cookie();
-	}
-
-	@Override
-	public void doCancel()
-	{
-		if (cookie == null)
-			return;
-
-		cookie.abort();
-	}
-
-	@Override
-	public void doCleanup()
-	{
-		if (cookie == null)
-			return;
-
-		cookie.destroy();
-		cookie = null;
-	}
-
-	@Override
-	public final Result doInBackground(Params ... params)
-	{
-		return doInBackground(cookie, params);
-	}
-
-	public abstract Result doInBackground(MuPDFCore.Cookie cookie, Params ... params);
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java
deleted file mode 100644
index 80174416..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java
+++ /dev/null
@@ -1,402 +0,0 @@
-package com.artifex.mupdfdemo;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.PointF;
-import android.graphics.RectF;
-
-import java.util.ArrayList;
-
-public class MuPDFCore
-{
-	/* load our native library */
-	private static boolean gs_so_available = false;
-	static {
-		System.out.println("Loading dll");
-		System.loadLibrary("mupdf_java");
-		System.out.println("Loaded dll");
-		if (gprfSupportedInternal())
-		{
-			try {
-				System.loadLibrary("gs");
-				gs_so_available = true;
-			}
-			catch (UnsatisfiedLinkError e) {
-				gs_so_available = false;
-			}
-		}
-	}
-
-	/* Readable members */
-	private int numPages = -1;
-	private float pageWidth;
-	private float pageHeight;
-	private long globals;
-	private byte fileBuffer[];
-	private String file_format;
-	private boolean isUnencryptedPDF;
-	private final boolean wasOpenedFromBuffer;
-
-	/* The native functions */
-	private static native boolean gprfSupportedInternal();
-	private native long openFile(String filename);
-	private native long openBuffer(String magic);
-	private native String fileFormatInternal();
-	private native boolean isUnencryptedPDFInternal();
-	private native int countPagesInternal();
-	private native void gotoPageInternal(int localActionPageNum);
-	private native float getPageWidth();
-	private native float getPageHeight();
-	private native void drawPage(Bitmap bitmap,
-			int pageW, int pageH,
-			int patchX, int patchY,
-			int patchW, int patchH,
-			long cookiePtr);
-	private native void updatePageInternal(Bitmap bitmap,
-			int page,
-			int pageW, int pageH,
-			int patchX, int patchY,
-			int patchW, int patchH,
-			long cookiePtr);
-	private native RectF[] searchPage(String text);
-	private native TextChar[][][][] text();
-	private native byte[] textAsHtml();
-	private native void addMarkupAnnotationInternal(PointF[] quadPoints, int type);
-	private native void addInkAnnotationInternal(PointF[][] arcs);
-	private native void deleteAnnotationInternal(int annot_index);
-	private native int passClickEventInternal(int page, float x, float y);
-	private native void setFocusedWidgetChoiceSelectedInternal(String [] selected);
-	private native String [] getFocusedWidgetChoiceSelected();
-	private native String [] getFocusedWidgetChoiceOptions();
-	private native int getFocusedWidgetSignatureState();
-	private native String checkFocusedSignatureInternal();
-	private native boolean signFocusedSignatureInternal(String keyFile, String password);
-	private native int setFocusedWidgetTextInternal(String text);
-	private native String getFocusedWidgetTextInternal();
-	private native int getFocusedWidgetTypeInternal();
-	private native LinkInfo [] getPageLinksInternal(int page);
-	private native RectF[] getWidgetAreasInternal(int page);
-	private native Annotation[] getAnnotationsInternal(int page);
-	private native OutlineItem [] getOutlineInternal();
-	private native boolean hasOutlineInternal();
-	private native boolean needsPasswordInternal();
-	private native boolean authenticatePasswordInternal(String password);
-	private native MuPDFAlertInternal waitForAlertInternal();
-	private native void replyToAlertInternal(MuPDFAlertInternal alert);
-	private native void startAlertsInternal();
-	private native void stopAlertsInternal();
-	private native void destroying();
-	private native boolean hasChangesInternal();
-	private native void saveInternal();
-	private native long createCookie();
-	private native void destroyCookie(long cookie);
-	private native void abortCookie(long cookie);
-
-	private native String startProofInternal(int resolution);
-	private native void endProofInternal(String filename);
-	private native int getNumSepsOnPageInternal(int page);
-	private native int controlSepOnPageInternal(int page, int sep, boolean disable);
-	private native Separation getSepInternal(int page, int sep);
-
-	public native boolean javascriptSupported();
-
-	public class Cookie
-	{
-		private final long cookiePtr;
-
-		public Cookie()
-		{
-			cookiePtr = createCookie();
-			if (cookiePtr == 0)
-				throw new OutOfMemoryError();
-		}
-
-		public void abort()
-		{
-			abortCookie(cookiePtr);
-		}
-
-		public void destroy()
-		{
-			// We could do this in finalize, but there's no guarantee that
-			// a finalize will occur before the muPDF context occurs.
-			destroyCookie(cookiePtr);
-		}
-	}
-
-	public MuPDFCore(Context context, String filename) throws Exception
-	{
-		globals = openFile(filename);
-		if (globals == 0)
-		{
-			throw new Exception(String.format(context.getString(R.string.cannot_open_file_Path), filename));
-		}
-		file_format = fileFormatInternal();
-		isUnencryptedPDF = isUnencryptedPDFInternal();
-		wasOpenedFromBuffer = false;
-	}
-
-	public MuPDFCore(Context context, byte buffer[], String magic) throws Exception {
-		fileBuffer = buffer;
-		globals = openBuffer(magic != null ? magic : "");
-		if (globals == 0)
-		{
-			throw new Exception(context.getString(R.string.cannot_open_buffer));
-		}
-		file_format = fileFormatInternal();
-		isUnencryptedPDF = isUnencryptedPDFInternal();
-		wasOpenedFromBuffer = true;
-	}
-
-	public int countPages()
-	{
-		if (numPages < 0)
-			numPages = countPagesSynchronized();
-		return numPages;
-	}
-
-	public String fileFormat()
-	{
-		return file_format;
-	}
-
-	public boolean isUnencryptedPDF()
-	{
-		return isUnencryptedPDF;
-	}
-
-	public boolean wasOpenedFromBuffer()
-	{
-		return wasOpenedFromBuffer;
-	}
-
-	private synchronized int countPagesSynchronized() {
-		return countPagesInternal();
-	}
-
-	/* Shim function */
-	private void gotoPage(int page)
-	{
-		if (page > numPages-1)
-			page = numPages-1;
-		else if (page < 0)
-			page = 0;
-		gotoPageInternal(page);
-		this.pageWidth = getPageWidth();
-		this.pageHeight = getPageHeight();
-	}
-
-	public synchronized PointF getPageSize(int page) {
-		gotoPage(page);
-		return new PointF(pageWidth, pageHeight);
-	}
-
-	public MuPDFAlert waitForAlert() {
-		MuPDFAlertInternal alert = waitForAlertInternal();
-		return alert != null ? alert.toAlert() : null;
-	}
-
-	public void replyToAlert(MuPDFAlert alert) {
-		replyToAlertInternal(new MuPDFAlertInternal(alert));
-	}
-
-	public void stopAlerts() {
-		stopAlertsInternal();
-	}
-
-	public void startAlerts() {
-		startAlertsInternal();
-	}
-
-	public synchronized void onDestroy() {
-		destroying();
-		globals = 0;
-	}
-
-	public synchronized void drawPage(Bitmap bm, int page,
-			int pageW, int pageH,
-			int patchX, int patchY,
-			int patchW, int patchH,
-			MuPDFCore.Cookie cookie) {
-		gotoPage(page);
-		drawPage(bm, pageW, pageH, patchX, patchY, patchW, patchH, cookie.cookiePtr);
-	}
-
-	public synchronized void updatePage(Bitmap bm, int page,
-			int pageW, int pageH,
-			int patchX, int patchY,
-			int patchW, int patchH,
-			MuPDFCore.Cookie cookie) {
-		updatePageInternal(bm, page, pageW, pageH, patchX, patchY, patchW, patchH, cookie.cookiePtr);
-	}
-
-	public synchronized PassClickResult passClickEvent(int page, float x, float y) {
-		boolean changed = passClickEventInternal(page, x, y) != 0;
-
-		switch (WidgetType.values()[getFocusedWidgetTypeInternal()])
-		{
-		case TEXT:
-			return new PassClickResultText(changed, getFocusedWidgetTextInternal());
-		case LISTBOX:
-		case COMBOBOX:
-			return new PassClickResultChoice(changed, getFocusedWidgetChoiceOptions(), getFocusedWidgetChoiceSelected());
-		case SIGNATURE:
-			return new PassClickResultSignature(changed, getFocusedWidgetSignatureState());
-		default:
-			return new PassClickResult(changed);
-		}
-
-	}
-
-	public synchronized boolean setFocusedWidgetText(int page, String text) {
-		boolean success;
-		gotoPage(page);
-		success = setFocusedWidgetTextInternal(text) != 0 ? true : false;
-
-		return success;
-	}
-
-	public synchronized void setFocusedWidgetChoiceSelected(String [] selected) {
-		setFocusedWidgetChoiceSelectedInternal(selected);
-	}
-
-	public synchronized String checkFocusedSignature() {
-		return checkFocusedSignatureInternal();
-	}
-
-	public synchronized boolean signFocusedSignature(String keyFile, String password) {
-		return signFocusedSignatureInternal(keyFile, password);
-	}
-
-	public synchronized LinkInfo [] getPageLinks(int page) {
-		return getPageLinksInternal(page);
-	}
-
-	public synchronized RectF [] getWidgetAreas(int page) {
-		return getWidgetAreasInternal(page);
-	}
-
-	public synchronized Annotation [] getAnnoations(int page) {
-		return getAnnotationsInternal(page);
-	}
-
-	public synchronized RectF [] searchPage(int page, String text) {
-		gotoPage(page);
-		return searchPage(text);
-	}
-
-	public synchronized byte[] html(int page) {
-		gotoPage(page);
-		return textAsHtml();
-	}
-
-	public synchronized TextWord [][] textLines(int page) {
-		gotoPage(page);
-		TextChar[][][][] chars = text();
-
-		// The text of the page held in a hierarchy (blocks, lines, spans).
-		// Currently we don't need to distinguish the blocks level or
-		// the spans, and we need to collect the text into words.
-		ArrayList<TextWord[]> lns = new ArrayList<TextWord[]>();
-
-		for (TextChar[][][] bl: chars) {
-			if (bl == null)
-				continue;
-			for (TextChar[][] ln: bl) {
-				ArrayList<TextWord> wds = new ArrayList<TextWord>();
-				TextWord wd = new TextWord();
-
-				for (TextChar[] sp: ln) {
-					for (TextChar tc: sp) {
-						if (tc.c != ' ') {
-							wd.Add(tc);
-						} else if (wd.w.length() > 0) {
-							wds.add(wd);
-							wd = new TextWord();
-						}
-					}
-				}
-
-				if (wd.w.length() > 0)
-					wds.add(wd);
-
-				if (wds.size() > 0)
-					lns.add(wds.toArray(new TextWord[wds.size()]));
-			}
-		}
-
-		return lns.toArray(new TextWord[lns.size()][]);
-	}
-
-	public synchronized void addMarkupAnnotation(int page, PointF[] quadPoints, Annotation.Type type) {
-		gotoPage(page);
-		addMarkupAnnotationInternal(quadPoints, type.ordinal());
-	}
-
-	public synchronized void addInkAnnotation(int page, PointF[][] arcs) {
-		gotoPage(page);
-		addInkAnnotationInternal(arcs);
-	}
-
-	public synchronized void deleteAnnotation(int page, int annot_index) {
-		gotoPage(page);
-		deleteAnnotationInternal(annot_index);
-	}
-
-	public synchronized boolean hasOutline() {
-		return hasOutlineInternal();
-	}
-
-	public synchronized OutlineItem [] getOutline() {
-		return getOutlineInternal();
-	}
-
-	public synchronized boolean needsPassword() {
-		return needsPasswordInternal();
-	}
-
-	public synchronized boolean authenticatePassword(String password) {
-		return authenticatePasswordInternal(password);
-	}
-
-	public synchronized boolean hasChanges() {
-		return hasChangesInternal();
-	}
-
-	public synchronized void save() {
-		saveInternal();
-	}
-
-	public synchronized String startProof(int resolution) {
-		return startProofInternal(resolution);
-	}
-
-	public synchronized void endProof(String filename) {
-		endProofInternal(filename);
-	}
-
-	public static boolean gprfSupported() {
-		if (gs_so_available == false)
-			return false;
-		return gprfSupportedInternal();
-	}
-
-	public boolean canProof()
-	{
-		String format = fileFormat();
-		if (format.contains("PDF"))
-			return true;
-		return false;
-	}
-
-	public synchronized int getNumSepsOnPage(int page) {
-		return getNumSepsOnPageInternal(page);
-	}
-
-	public synchronized int controlSepOnPage(int page, int sep, boolean disable) {
-		return controlSepOnPageInternal(page, sep, disable);
-	}
-
-	public synchronized Separation getSep(int page, int sep) {
-		return getSepInternal(page, sep);
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFPageAdapter.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFPageAdapter.java
deleted file mode 100644
index abdac845..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFPageAdapter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-
-public class MuPDFPageAdapter extends BaseAdapter {
-	private final Context mContext;
-	private final FilePicker.FilePickerSupport mFilePickerSupport;
-	private final MuPDFCore mCore;
-	private final SparseArray<PointF> mPageSizes = new SparseArray<PointF>();
-	private       Bitmap mSharedHqBm;
-
-	public MuPDFPageAdapter(Context c, FilePicker.FilePickerSupport filePickerSupport, MuPDFCore core) {
-		mContext = c;
-		mFilePickerSupport = filePickerSupport;
-		mCore = core;
-	}
-
-	public int getCount() {
-		return mCore.countPages();
-	}
-
-	public Object getItem(int position) {
-		return null;
-	}
-
-	public long getItemId(int position) {
-		return 0;
-	}
-
-	public void releaseBitmaps()
-	{
-		//  recycle and release the shared bitmap.
-		if (mSharedHqBm!=null)
-			mSharedHqBm.recycle();
-		mSharedHqBm = null;
-	}
-
-	public View getView(final int position, View convertView, ViewGroup parent) {
-		final MuPDFPageView pageView;
-		if (convertView == null) {
-			if (mSharedHqBm == null || mSharedHqBm.getWidth() != parent.getWidth() || mSharedHqBm.getHeight() != parent.getHeight())
-				mSharedHqBm = Bitmap.createBitmap(parent.getWidth(), parent.getHeight(), Bitmap.Config.ARGB_8888);
-
-			pageView = new MuPDFPageView(mContext, mFilePickerSupport, mCore, new Point(parent.getWidth(), parent.getHeight()), mSharedHqBm);
-		} else {
-			pageView = (MuPDFPageView) convertView;
-		}
-
-		PointF pageSize = mPageSizes.get(position);
-		if (pageSize != null) {
-			// We already know the page size. Set it up
-			// immediately
-			pageView.setPage(position, pageSize);
-		} else {
-			// Page size as yet unknown. Blank it for now, and
-			// start a background task to find the size
-			pageView.blank(position);
-			AsyncTask<Void,Void,PointF> sizingTask = new AsyncTask<Void,Void,PointF>() {
-				@Override
-				protected PointF doInBackground(Void... arg0) {
-					return mCore.getPageSize(position);
-				}
-
-				@Override
-				protected void onPostExecute(PointF result) {
-					super.onPostExecute(result);
-					// We now know the page size
-					mPageSizes.put(position, result);
-					// Check that this view hasn't been reused for
-					// another page since we started
-					if (pageView.getPage() == position)
-						pageView.setPage(position, result);
-				}
-			};
-
-			sizingTask.execute((Void)null);
-		}
-		return pageView;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFPageView.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
deleted file mode 100644
index ff6b6bbb..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
+++ /dev/null
@@ -1,692 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import java.util.ArrayList;
-
-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 cooresponding 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.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.
-				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
-						Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
-					bm.eraseColor(0);
-				mCore.updatePage(bm, mPageNumber, sizeX, sizeY, patchX, patchY, patchWidth, patchHeight, cookie);
-				return null;
-			}
-		};
-	}
-
-	@Override
-	protected LinkInfo[] getLinkInfo() {
-		return mCore.getPageLinks(mPageNumber);
-	}
-
-	@Override
-	protected TextWord[][] getText() {
-		return mCore.textLines(mPageNumber);
-	}
-
-	@Override
-	protected void addMarkup(PointF[] quadPoints, Annotation.Type type) {
-		mCore.addMarkupAnnotation(mPageNumber, quadPoints, type);
-	}
-
-	private void loadAnnotations() {
-		mAnnotations = null;
-		if (mLoadAnnotations != null)
-			mLoadAnnotations.cancel(true);
-		mLoadAnnotations = new AsyncTask<Void,Void,Annotation[]> () {
-			@Override
-			protected Annotation[] doInBackground(Void... params) {
-				return mCore.getAnnoations(mPageNumber);
-			}
-
-			@Override
-			protected void onPostExecute(Annotation[] result) {
-				mAnnotations = result;
-			}
-		};
-
-		mLoadAnnotations.execute();
-	}
-
-	@Override
-	public void setPage(final int page, PointF size) {
-		loadAnnotations();
-
-		mLoadWidgetAreas = new AsyncTask<Void,Void,RectF[]> () {
-			@Override
-			protected RectF[] doInBackground(Void... arg0) {
-				return mCore.getWidgetAreas(page);
-			}
-
-			@Override
-			protected void onPostExecute(RectF[] result) {
-				mWidgetAreas = result;
-			}
-		};
-
-		mLoadWidgetAreas.execute();
-
-		super.setPage(page, size);
-	}
-
-	public void setScale(float scale) {
-		// This type of view scales automatically to fit the size
-		// determined by the parent view groups during layout
-	}
-
-	@Override
-	public void releaseResources() {
-		if (mPassClick != null) {
-			mPassClick.cancel(true);
-			mPassClick = null;
-		}
-
-		if (mLoadWidgetAreas != null) {
-			mLoadWidgetAreas.cancel(true);
-			mLoadWidgetAreas = null;
-		}
-
-		if (mLoadAnnotations != null) {
-			mLoadAnnotations.cancel(true);
-			mLoadAnnotations = null;
-		}
-
-		if (mSetWidgetText != null) {
-			mSetWidgetText.cancel(true);
-			mSetWidgetText = null;
-		}
-
-		if (mSetWidgetChoice != null) {
-			mSetWidgetChoice.cancel(true);
-			mSetWidgetChoice = null;
-		}
-
-		if (mAddStrikeOut != null) {
-			mAddStrikeOut.cancel(true);
-			mAddStrikeOut = null;
-		}
-
-		if (mDeleteAnnotation != null) {
-			mDeleteAnnotation.cancel(true);
-			mDeleteAnnotation = null;
-		}
-
-		super.releaseResources();
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFReaderView.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFReaderView.java
deleted file mode 100644
index f2d7f8fe..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFReaderView.java
+++ /dev/null
@@ -1,276 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.View;
-import android.view.WindowManager;
-
-public class MuPDFReaderView extends ReaderView {
-	public enum Mode {Viewing, Selecting, Drawing}
-	private final Context mContext;
-	private boolean mLinksEnabled = false;
-	private Mode mMode = Mode.Viewing;
-	private boolean tapDisabled = false;
-	private int tapPageMargin;
-
-	protected void onTapMainDocArea() {}
-	protected void onDocMotion() {}
-	protected void onHit(Hit item) {};
-
-	public void setLinksEnabled(boolean b) {
-		mLinksEnabled = b;
-		resetupChildren();
-	}
-
-	public void setMode(Mode m) {
-		mMode = m;
-	}
-
-	private void setup()
-	{
-		// Get the screen size etc to customise tap margins.
-		// We calculate the size of 1 inch of the screen for tapping.
-		// On some devices the dpi values returned are wrong, so we
-		// sanity check it: we first restrict it so that we are never
-		// less than 100 pixels (the smallest Android device screen
-		// dimension I've seen is 480 pixels or so). Then we check
-		// to ensure we are never more than 1/5 of the screen width.
-		DisplayMetrics dm = new DisplayMetrics();
-		WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-		wm.getDefaultDisplay().getMetrics(dm);
-		tapPageMargin = (int)dm.xdpi;
-		if (tapPageMargin < 100)
-			tapPageMargin = 100;
-		if (tapPageMargin > dm.widthPixels/5)
-			tapPageMargin = dm.widthPixels/5;
-	}
-
-	public MuPDFReaderView(Context context) {
-		super(context);
-		mContext = context;
-		setup();
-	}
-
-	public MuPDFReaderView(Context context, AttributeSet attrs)
-	{
-		super(context, attrs);
-		mContext = context;
-		setup();
-	}
-
-	public boolean onSingleTapUp(MotionEvent e) {
-		LinkInfo link = null;
-
-		if (mMode == Mode.Viewing && !tapDisabled) {
-			MuPDFView pageView = (MuPDFView) getDisplayedView();
-			Hit item = pageView.passClickEvent(e.getX(), e.getY());
-			onHit(item);
-			if (item == Hit.Nothing) {
-				if (mLinksEnabled && pageView != null
-				&& (link = pageView.hitLink(e.getX(), e.getY())) != null) {
-					link.acceptVisitor(new LinkInfoVisitor() {
-						@Override
-						public void visitInternal(LinkInfoInternal li) {
-							// Clicked on an internal (GoTo) link
-							setDisplayedViewIndex(li.pageNumber);
-						}
-
-						@Override
-						public void visitExternal(LinkInfoExternal li) {
-							Intent intent = new Intent(Intent.ACTION_VIEW, Uri
-									.parse(li.url));
-							mContext.startActivity(intent);
-						}
-
-						@Override
-						public void visitRemote(LinkInfoRemote li) {
-							// Clicked on a remote (GoToR) link
-						}
-					});
-				} else if (e.getX() < tapPageMargin) {
-					super.smartMoveBackwards();
-				} else if (e.getX() > super.getWidth() - tapPageMargin) {
-					super.smartMoveForwards();
-				} else if (e.getY() < tapPageMargin) {
-					super.smartMoveBackwards();
-				} else if (e.getY() > super.getHeight() - tapPageMargin) {
-					super.smartMoveForwards();
-				} else {
-					onTapMainDocArea();
-				}
-			}
-		}
-		return super.onSingleTapUp(e);
-	}
-
-	@Override
-	public boolean onDown(MotionEvent e) {
-
-		return super.onDown(e);
-	}
-
-	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
-			float distanceY) {
-		MuPDFView pageView = (MuPDFView)getDisplayedView();
-		switch (mMode) {
-		case Viewing:
-			if (!tapDisabled)
-				onDocMotion();
-
-			return super.onScroll(e1, e2, distanceX, distanceY);
-		case Selecting:
-			if (pageView != null)
-				pageView.selectText(e1.getX(), e1.getY(), e2.getX(), e2.getY());
-			return true;
-		default:
-			return true;
-		}
-	}
-
-	@Override
-	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
-			float velocityY) {
-		switch (mMode) {
-		case Viewing:
-			return super.onFling(e1, e2, velocityX, velocityY);
-		default:
-			return true;
-		}
-	}
-
-	public boolean onScaleBegin(ScaleGestureDetector d) {
-		// Disabled showing the buttons until next touch.
-		// Not sure why this is needed, but without it
-		// pinch zoom can make the buttons appear
-		tapDisabled = true;
-		return super.onScaleBegin(d);
-	}
-
-	public boolean onTouchEvent(MotionEvent event) {
-
-		if ( mMode == Mode.Drawing )
-		{
-			float x = event.getX();
-			float y = event.getY();
-			switch (event.getAction())
-			{
-				case MotionEvent.ACTION_DOWN:
-					touch_start(x, y);
-					break;
-				case MotionEvent.ACTION_MOVE:
-					touch_move(x, y);
-					break;
-				case MotionEvent.ACTION_UP:
-					touch_up();
-					break;
-			}
-		}
-
-		if ((event.getAction() & event.getActionMasked()) == MotionEvent.ACTION_DOWN)
-		{
-			tapDisabled = false;
-		}
-
-		return super.onTouchEvent(event);
-	}
-
-	private float mX, mY;
-
-	private static final float TOUCH_TOLERANCE = 2;
-
-	private void touch_start(float x, float y) {
-
-		MuPDFView pageView = (MuPDFView)getDisplayedView();
-		if (pageView != null)
-		{
-			pageView.startDraw(x, y);
-		}
-		mX = x;
-		mY = y;
-	}
-
-	private void touch_move(float x, float y) {
-
-		float dx = Math.abs(x - mX);
-		float dy = Math.abs(y - mY);
-		if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
-		{
-			MuPDFView pageView = (MuPDFView)getDisplayedView();
-			if (pageView != null)
-			{
-				pageView.continueDraw(x, y);
-			}
-			mX = x;
-			mY = y;
-		}
-	}
-
-	private void touch_up() {
-
-		// NOOP
-	}
-
-	protected void onChildSetup(int i, View v) {
-		if (SearchTaskResult.get() != null
-				&& SearchTaskResult.get().pageNumber == i)
-			((MuPDFView) v).setSearchBoxes(SearchTaskResult.get().searchBoxes);
-		else
-			((MuPDFView) v).setSearchBoxes(null);
-
-		((MuPDFView) v).setLinkHighlighting(mLinksEnabled);
-
-		((MuPDFView) v).setChangeReporter(new Runnable() {
-			public void run() {
-				applyToChildren(new ReaderView.ViewMapper() {
-					@Override
-					void applyToView(View view) {
-						((MuPDFView) view).update();
-					}
-				});
-			}
-		});
-	}
-
-	protected void onMoveToChild(int i) {
-		if (SearchTaskResult.get() != null
-				&& SearchTaskResult.get().pageNumber != i) {
-			SearchTaskResult.set(null);
-			resetupChildren();
-		}
-	}
-
-	@Override
-	protected void onMoveOffChild(int i) {
-		View v = getView(i);
-		if (v != null)
-			((MuPDFView)v).deselectAnnotation();
-	}
-
-	protected void onSettle(View v) {
-		// When the layout has settled ask the page to render
-		// in HQ
-		((MuPDFView) v).updateHq(false);
-	}
-
-	protected void onUnsettle(View v) {
-		// When something changes making the previous settled view
-		// no longer appropriate, tell the page to remove HQ
-		((MuPDFView) v).removeHq();
-	}
-
-	@Override
-	protected void onNotInUse(View v) {
-		((MuPDFView) v).releaseResources();
-	}
-
-	@Override
-	protected void onScaleChild(View v, Float scale) {
-		((MuPDFView) v).setScale(scale);
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFReflowAdapter.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFReflowAdapter.java
deleted file mode 100644
index 48625a7e..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFReflowAdapter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-
-public class MuPDFReflowAdapter extends BaseAdapter {
-	private final Context mContext;
-	private final MuPDFCore mCore;
-
-	public MuPDFReflowAdapter(Context c, MuPDFCore core) {
-		mContext = c;
-		mCore = core;
-	}
-
-	public int getCount() {
-		return mCore.countPages();
-	}
-
-	public Object getItem(int arg0) {
-		return null;
-	}
-
-	public long getItemId(int arg0) {
-		return 0;
-	}
-
-	public View getView(int position, View convertView, ViewGroup parent) {
-		final MuPDFReflowView reflowView;
-		if (convertView == null) {
-			reflowView = new MuPDFReflowView(mContext, mCore, new Point(parent.getWidth(), parent.getHeight()));
-		} else {
-			reflowView = (MuPDFReflowView) convertView;
-		}
-
-		reflowView.setPage(position, new PointF());
-
-		return reflowView;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFReflowView.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFReflowView.java
deleted file mode 100644
index 7d41a9b9..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFReflowView.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.os.Handler;
-import android.util.Base64;
-import android.view.MotionEvent;
-import android.view.View;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-public class MuPDFReflowView extends WebView implements MuPDFView {
-	private final MuPDFCore mCore;
-	private final Handler mHandler;
-	private final Point mParentSize;
-	private int mPage;
-	private float mScale;
-	private int mContentHeight;
-	AsyncTask<Void,Void,byte[]> mLoadHTML;
-
-	public MuPDFReflowView(Context c, MuPDFCore core, Point parentSize) {
-		super(c);
-		mHandler = new Handler();
-		mCore = core;
-		mParentSize = parentSize;
-		mScale = 1.0f;
-		mContentHeight = parentSize.y;
-		getSettings().setJavaScriptEnabled(true);
-		addJavascriptInterface(new Object(){
-			public void reportContentHeight(String value) {
-				mContentHeight = (int)Float.parseFloat(value);
-				mHandler.post(new Runnable() {
-					public void run() {
-						requestLayout();
-					}
-				});
-			}
-		}, "HTMLOUT");
-		setWebViewClient(new WebViewClient() {
-			@Override
-			public void onPageFinished(WebView view, String url) {
-				setScale(mScale);
-			}
-		});
-	}
-
-	private void requestHeight() {
-		// Get the webview to report the content height via the interface setup
-		// above. Workaround for getContentHeight not working
-		loadUrl("javascript:elem=document.getElementById('content');window.HTMLOUT.reportContentHeight("+mParentSize.x+"*elem.offsetHeight/elem.offsetWidth)");
-	}
-
-	public void setPage(int page, PointF size) {
-		mPage = page;
-		if (mLoadHTML != null) {
-			mLoadHTML.cancel(true);
-		}
-		mLoadHTML = new AsyncTask<Void,Void,byte[]>() {
-			@Override
-			protected byte[] doInBackground(Void... params) {
-				return mCore.html(mPage);
-			}
-			@Override
-			protected void onPostExecute(byte[] result) {
-				String b64 = Base64.encodeToString(result, Base64.DEFAULT);
-				loadData(b64, "text/html; charset=utf-8", "base64");
-			}
-		};
-		mLoadHTML.execute();
-	}
-
-	public int getPage() {
-		return mPage;
-	}
-
-	public void setScale(float scale) {
-		mScale = scale;
-		loadUrl("javascript:document.getElementById('content').style.zoom=\""+(int)(mScale*100)+"%\"");
-		requestHeight();
-	}
-
-	public void blank(int page) {
-	}
-
-	public Hit passClickEvent(float x, float y) {
-		return Hit.Nothing;
-	}
-
-	public LinkInfo hitLink(float x, float y) {
-		return null;
-	}
-
-	public void selectText(float x0, float y0, float x1, float y1) {
-	}
-
-	public void deselectText() {
-	}
-
-	public boolean copySelection() {
-		return false;
-	}
-
-	public boolean markupSelection(Annotation.Type type) {
-		return false;
-	}
-
-	public void startDraw(float x, float y) {
-	}
-
-	public void continueDraw(float x, float y) {
-	}
-
-	public void cancelDraw() {
-	}
-
-	public boolean saveDraw() {
-		return false;
-	}
-
-	public void setSearchBoxes(RectF[] searchBoxes) {
-	}
-
-	public void setLinkHighlighting(boolean f) {
-	}
-
-	public void deleteSelectedAnnotation() {
-	}
-
-	public void deselectAnnotation() {
-	}
-
-	public void setChangeReporter(Runnable reporter) {
-	}
-
-	public void update() {
-	}
-
-	public void updateHq(boolean update) {
-	}
-
-	public void removeHq() {
-	}
-
-	public void releaseResources() {
-		if (mLoadHTML != null) {
-			mLoadHTML.cancel(true);
-			mLoadHTML = null;
-		}
-	}
-
-	public void releaseBitmaps() {
-	}
-
-	@Override
-	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-		int x, y;
-		switch(View.MeasureSpec.getMode(widthMeasureSpec)) {
-		case View.MeasureSpec.UNSPECIFIED:
-			x = mParentSize.x;
-			break;
-		default:
-			x = View.MeasureSpec.getSize(widthMeasureSpec);
-		}
-		switch(View.MeasureSpec.getMode(heightMeasureSpec)) {
-		case View.MeasureSpec.UNSPECIFIED:
-			y = mContentHeight;
-			break;
-		default:
-			y = View.MeasureSpec.getSize(heightMeasureSpec);
-		}
-
-		setMeasuredDimension(x, y);
-	}
-
-	@Override
-	public boolean onTouchEvent(MotionEvent ev) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFView.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFView.java
deleted file mode 100644
index ec3d3d9a..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFView.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.graphics.PointF;
-import android.graphics.RectF;
-
-enum Hit {Nothing, Widget, Annotation};
-
-public interface MuPDFView {
-	public void setPage(int page, PointF size);
-	public void setScale(float scale);
-	public int getPage();
-	public void blank(int page);
-	public Hit passClickEvent(float x, float y);
-	public LinkInfo hitLink(float x, float y);
-	public void selectText(float x0, float y0, float x1, float y1);
-	public void deselectText();
-	public boolean copySelection();
-	public boolean markupSelection(Annotation.Type type);
-	public void deleteSelectedAnnotation();
-	public void setSearchBoxes(RectF searchBoxes[]);
-	public void setLinkHighlighting(boolean f);
-	public void deselectAnnotation();
-	public void startDraw(float x, float y);
-	public void continueDraw(float x, float y);
-	public void cancelDraw();
-	public boolean saveDraw();
-	public void setChangeReporter(Runnable reporter);
-	public void update();
-	public void updateHq(boolean update);
-	public void removeHq();
-	public void releaseResources();
-	public void releaseBitmaps();
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/OutlineActivity.java b/platform/android/src/com/artifex/mupdfdemo/OutlineActivity.java
deleted file mode 100644
index 52b0d410..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/OutlineActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.app.ListActivity;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ListView;
-
-public class OutlineActivity extends ListActivity {
-	OutlineItem mItems[];
-
-	/** Called when the activity is first created. */
-	@Override
-	public void onCreate(Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-
-		mItems = OutlineActivityData.get().items;
-		setListAdapter(new OutlineAdapter(getLayoutInflater(),mItems));
-		// Restore the position within the list from last viewing
-		getListView().setSelection(OutlineActivityData.get().position);
-		getListView().setDividerHeight(0);
-		setResult(-1);
-	}
-
-	@Override
-	protected void onListItemClick(ListView l, View v, int position, long id) {
-		super.onListItemClick(l, v, position, id);
-		OutlineActivityData.get().position = getListView().getFirstVisiblePosition();
-		setResult(mItems[position].page);
-		finish();
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/OutlineActivityData.java b/platform/android/src/com/artifex/mupdfdemo/OutlineActivityData.java
deleted file mode 100644
index a703e61e..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/OutlineActivityData.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public class OutlineActivityData {
-	public OutlineItem items[];
-	public int         position;
-	static private OutlineActivityData singleton;
-
-	static public void set(OutlineActivityData d) {
-		singleton = d;
-	}
-
-	static public OutlineActivityData get() {
-		if (singleton == null)
-			singleton = new OutlineActivityData();
-		return singleton;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/OutlineAdapter.java b/platform/android/src/com/artifex/mupdfdemo/OutlineAdapter.java
deleted file mode 100644
index 4251ed8e..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/OutlineAdapter.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-public class OutlineAdapter extends BaseAdapter {
-	private final OutlineItem    mItems[];
-	private final LayoutInflater mInflater;
-	public OutlineAdapter(LayoutInflater inflater, OutlineItem items[]) {
-		mInflater = inflater;
-		mItems    = items;
-	}
-
-	public int getCount() {
-		return mItems.length;
-	}
-
-	public Object getItem(int arg0) {
-		return null;
-	}
-
-	public long getItemId(int arg0) {
-		return 0;
-	}
-
-	public View getView(int position, View convertView, ViewGroup parent) {
-		View v;
-		if (convertView == null) {
-			v = mInflater.inflate(R.layout.outline_entry, null);
-		} else {
-			v = convertView;
-		}
-		int level = mItems[position].level;
-		if (level > 8) level = 8;
-		String space = "";
-		for (int i=0; i<level;i++)
-			space += "   ";
-		((TextView)v.findViewById(R.id.title)).setText(space+mItems[position].title);
-		((TextView)v.findViewById(R.id.page)).setText(String.valueOf(mItems[position].page+1));
-		return v;
-	}
-
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/OutlineItem.java b/platform/android/src/com/artifex/mupdfdemo/OutlineItem.java
deleted file mode 100644
index 7730991e..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/OutlineItem.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public class OutlineItem {
-	public final int    level;
-	public final String title;
-	public final int    page;
-
-	OutlineItem(int _level, String _title, int _page) {
-		level = _level;
-		title = _title;
-		page  = _page;
-	}
-
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/PageView.java b/platform/android/src/com/artifex/mupdfdemo/PageView.java
deleted file mode 100644
index 2ee407cb..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/PageView.java
+++ /dev/null
@@ -1,698 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.os.Handler;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-
-// Make our ImageViews opaque to optimize redraw
-class OpaqueImageView extends ImageView {
-
-	public OpaqueImageView(Context context) {
-		super(context);
-	}
-
-	@Override
-	public boolean isOpaque() {
-		return true;
-	}
-}
-
-interface TextProcessor {
-	void onStartLine();
-	void onWord(TextWord word);
-	void onEndLine();
-}
-
-class TextSelector {
-	final private TextWord[][] mText;
-	final private RectF mSelectBox;
-
-	public TextSelector(TextWord[][] text, RectF selectBox) {
-		mText = text;
-		mSelectBox = selectBox;
-	}
-
-	public void select(TextProcessor tp) {
-		if (mText == null || mSelectBox == null)
-			return;
-
-		ArrayList<TextWord[]> lines = new ArrayList<TextWord[]>();
-		for (TextWord[] line : mText)
-			if (line[0].bottom > mSelectBox.top && line[0].top < mSelectBox.bottom)
-				lines.add(line);
-
-		Iterator<TextWord[]> it = lines.iterator();
-		while (it.hasNext()) {
-			TextWord[] line = it.next();
-			boolean firstLine = line[0].top < mSelectBox.top;
-			boolean lastLine = line[0].bottom > mSelectBox.bottom;
-			float start = Float.NEGATIVE_INFINITY;
-			float end = Float.POSITIVE_INFINITY;
-
-			if (firstLine && lastLine) {
-				start = Math.min(mSelectBox.left, mSelectBox.right);
-				end = Math.max(mSelectBox.left, mSelectBox.right);
-			} else if (firstLine) {
-				start = mSelectBox.left;
-			} else if (lastLine) {
-				end = mSelectBox.right;
-			}
-
-			tp.onStartLine();
-
-			for (TextWord word : line)
-				if (word.right > start && word.left < end)
-					tp.onWord(word);
-
-			tp.onEndLine();
-		}
-	}
-}
-
-public abstract class PageView extends ViewGroup {
-	private static final int HIGHLIGHT_COLOR = 0x802572AC;
-	private static final int LINK_COLOR = 0x80AC7225;
-	private static final int BOX_COLOR = 0xFF4444FF;
-	private static final int INK_COLOR = 0xFFFF0000;
-	private static final float INK_THICKNESS = 10.0f;
-	private static final int BACKGROUND_COLOR = 0xFFFFFFFF;
-	private static final int PROGRESS_DIALOG_DELAY = 200;
-	protected final Context   mContext;
-	protected     int       mPageNumber;
-	private       Point     mParentSize;
-	protected     Point     mSize;   // Size of page at minimum zoom
-	protected     float     mSourceScale;
-
-	private       ImageView mEntire; // Image rendered at minimum zoom
-	private       Bitmap    mEntireBm;
-	private       Matrix    mEntireMat;
-	private       AsyncTask<Void,Void,TextWord[][]> mGetText;
-	private       AsyncTask<Void,Void,LinkInfo[]> mGetLinkInfo;
-	private       CancellableAsyncTask<Void, Void> mDrawEntire;
-
-	private       Point     mPatchViewSize; // View size on the basis of which the patch was created
-	private       Rect      mPatchArea;
-	private       ImageView mPatch;
-	private       Bitmap    mPatchBm;
-	private       CancellableAsyncTask<Void,Void> mDrawPatch;
-	private       RectF     mSearchBoxes[];
-	protected     LinkInfo  mLinks[];
-	private       RectF     mSelectBox;
-	private       TextWord  mText[][];
-	private       RectF     mItemSelectBox;
-	protected     ArrayList<ArrayList<PointF>> mDrawing;
-	private       View      mSearchView;
-	private       boolean   mIsBlank;
-	private       boolean   mHighlightLinks;
-
-	private       ProgressBar mBusyIndicator;
-	private final Handler   mHandler = new Handler();
-
-	public PageView(Context c, Point parentSize, Bitmap sharedHqBm) {
-		super(c);
-		mContext    = c;
-		mParentSize = parentSize;
-		setBackgroundColor(BACKGROUND_COLOR);
-		mEntireBm = Bitmap.createBitmap(parentSize.x, parentSize.y, Config.ARGB_8888);
-		mPatchBm = sharedHqBm;
-		mEntireMat = new Matrix();
-	}
-
-	protected abstract CancellableTaskDefinition<Void, Void> getDrawPageTask(Bitmap bm, int sizeX, int sizeY, int patchX, int patchY, int patchWidth, int patchHeight);
-	protected abstract CancellableTaskDefinition<Void, Void> getUpdatePageTask(Bitmap bm, int sizeX, int sizeY, int patchX, int patchY, int patchWidth, int patchHeight);
-	protected abstract LinkInfo[] getLinkInfo();
-	protected abstract TextWord[][] getText();
-	protected abstract void addMarkup(PointF[] quadPoints, Annotation.Type type);
-
-	private void reinit() {
-		// Cancel pending render task
-		if (mDrawEntire != null) {
-			mDrawEntire.cancelAndWait();
-			mDrawEntire = null;
-		}
-
-		if (mDrawPatch != null) {
-			mDrawPatch.cancelAndWait();
-			mDrawPatch = null;
-		}
-
-		if (mGetLinkInfo != null) {
-			mGetLinkInfo.cancel(true);
-			mGetLinkInfo = null;
-		}
-
-		if (mGetText != null) {
-			mGetText.cancel(true);
-			mGetText = null;
-		}
-
-		mIsBlank = true;
-		mPageNumber = 0;
-
-		if (mSize == null)
-			mSize = mParentSize;
-
-		if (mEntire != null) {
-			mEntire.setImageBitmap(null);
-			mEntire.invalidate();
-		}
-
-		if (mPatch != null) {
-			mPatch.setImageBitmap(null);
-			mPatch.invalidate();
-		}
-
-		mPatchViewSize = null;
-		mPatchArea = null;
-
-		mSearchBoxes = null;
-		mLinks = null;
-		mSelectBox = null;
-		mText = null;
-		mItemSelectBox = null;
-	}
-
-	public void releaseResources() {
-		reinit();
-
-		if (mBusyIndicator != null) {
-			removeView(mBusyIndicator);
-			mBusyIndicator = null;
-		}
-	}
-
-	public void releaseBitmaps() {
-		reinit();
-
-		//  recycle bitmaps before releasing them.
-
-		if (mEntireBm!=null)
-			mEntireBm.recycle();
-		mEntireBm = null;
-
-		if (mPatchBm!=null)
-			mPatchBm.recycle();
-		mPatchBm = null;
-	}
-
-	public void blank(int page) {
-		reinit();
-		mPageNumber = page;
-
-		if (mBusyIndicator == null) {
-			mBusyIndicator = new ProgressBar(mContext);
-			mBusyIndicator.setIndeterminate(true);
-			mBusyIndicator.setBackgroundResource(R.drawable.busy);
-			addView(mBusyIndicator);
-		}
-
-		setBackgroundColor(BACKGROUND_COLOR);
-	}
-
-	public void setPage(int page, PointF size) {
-		// Cancel pending render task
-		if (mDrawEntire != null) {
-			mDrawEntire.cancelAndWait();
-			mDrawEntire = null;
-		}
-
-		mIsBlank = false;
-		// Highlights may be missing because mIsBlank was true on last draw
-		if (mSearchView != null)
-			mSearchView.invalidate();
-
-		mPageNumber = page;
-		if (mEntire == null) {
-			mEntire = new OpaqueImageView(mContext);
-			mEntire.setScaleType(ImageView.ScaleType.MATRIX);
-			addView(mEntire);
-		}
-
-		// Calculate scaled size that fits within the screen limits
-		// This is the size at minimum zoom
-		mSourceScale = Math.min(mParentSize.x/size.x, mParentSize.y/size.y);
-		Point newSize = new Point((int)(size.x*mSourceScale), (int)(size.y*mSourceScale));
-		mSize = newSize;
-
-		mEntire.setImageBitmap(null);
-		mEntire.invalidate();
-
-		// Get the link info in the background
-		mGetLinkInfo = new AsyncTask<Void,Void,LinkInfo[]>() {
-			protected LinkInfo[] doInBackground(Void... v) {
-				return getLinkInfo();
-			}
-
-			protected void onPostExecute(LinkInfo[] v) {
-				mLinks = v;
-				if (mSearchView != null)
-					mSearchView.invalidate();
-			}
-		};
-
-		mGetLinkInfo.execute();
-
-		// Render the page in the background
-		mDrawEntire = new CancellableAsyncTask<Void, Void>(getDrawPageTask(mEntireBm, mSize.x, mSize.y, 0, 0, mSize.x, mSize.y)) {
-
-			@Override
-			public void onPreExecute() {
-				setBackgroundColor(BACKGROUND_COLOR);
-				mEntire.setImageBitmap(null);
-				mEntire.invalidate();
-
-				if (mBusyIndicator == null) {
-					mBusyIndicator = new ProgressBar(mContext);
-					mBusyIndicator.setIndeterminate(true);
-					mBusyIndicator.setBackgroundResource(R.drawable.busy);
-					addView(mBusyIndicator);
-					mBusyIndicator.setVisibility(INVISIBLE);
-					mHandler.postDelayed(new Runnable() {
-						public void run() {
-							if (mBusyIndicator != null)
-								mBusyIndicator.setVisibility(VISIBLE);
-						}
-					}, PROGRESS_DIALOG_DELAY);
-				}
-			}
-
-			@Override
-			public void onPostExecute(Void result) {
-				removeView(mBusyIndicator);
-				mBusyIndicator = null;
-				mEntire.setImageBitmap(mEntireBm);
-				mEntire.invalidate();
-				setBackgroundColor(Color.TRANSPARENT);
-
-			}
-		};
-
-		mDrawEntire.execute();
-
-		if (mSearchView == null) {
-			mSearchView = new View(mContext) {
-				@Override
-				protected void onDraw(final Canvas canvas) {
-					super.onDraw(canvas);
-					// Work out current total scale factor
-					// from source to view
-					final float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
-					final Paint paint = new Paint();
-
-					if (!mIsBlank && mSearchBoxes != null) {
-						paint.setColor(HIGHLIGHT_COLOR);
-						for (RectF rect : mSearchBoxes)
-							canvas.drawRect(rect.left*scale, rect.top*scale,
-									        rect.right*scale, rect.bottom*scale,
-									        paint);
-					}
-
-					if (!mIsBlank && mLinks != null && mHighlightLinks) {
-						paint.setColor(LINK_COLOR);
-						for (LinkInfo link : mLinks)
-							canvas.drawRect(link.rect.left*scale, link.rect.top*scale,
-									        link.rect.right*scale, link.rect.bottom*scale,
-									        paint);
-					}
-
-					if (mSelectBox != null && mText != null) {
-						paint.setColor(HIGHLIGHT_COLOR);
-						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())
-									canvas.drawRect(rect.left*scale, rect.top*scale, rect.right*scale, rect.bottom*scale, paint);
-							}
-						});
-					}
-
-					if (mItemSelectBox != null) {
-						paint.setStyle(Paint.Style.STROKE);
-						paint.setColor(BOX_COLOR);
-						canvas.drawRect(mItemSelectBox.left*scale, mItemSelectBox.top*scale, mItemSelectBox.right*scale, mItemSelectBox.bottom*scale, paint);
-					}
-
-					if (mDrawing != null) {
-						Path path = new Path();
-						PointF p;
-
-						paint.setAntiAlias(true);
-						paint.setDither(true);
-						paint.setStrokeJoin(Paint.Join.ROUND);
-						paint.setStrokeCap(Paint.Cap.ROUND);
-
-						paint.setStyle(Paint.Style.FILL);
-						paint.setStrokeWidth(INK_THICKNESS * scale);
-						paint.setColor(INK_COLOR);
-
-						Iterator<ArrayList<PointF>> it = mDrawing.iterator();
-						while (it.hasNext()) {
-							ArrayList<PointF> arc = it.next();
-							if (arc.size() >= 2) {
-								Iterator<PointF> iit = arc.iterator();
-								p = iit.next();
-								float mX = p.x * scale;
-								float mY = p.y * scale;
-								path.moveTo(mX, mY);
-								while (iit.hasNext()) {
-									p = iit.next();
-									float x = p.x * scale;
-									float y = p.y * scale;
-									path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
-									mX = x;
-									mY = y;
-								}
-								path.lineTo(mX, mY);
-							} else {
-								p = arc.get(0);
-								canvas.drawCircle(p.x * scale, p.y * scale, INK_THICKNESS * scale / 2, paint);
-							}
-						}
-
-						paint.setStyle(Paint.Style.STROKE);
-						canvas.drawPath(path, paint);
-					}
-				}
-			};
-
-			addView(mSearchView);
-		}
-		requestLayout();
-	}
-
-	public void setSearchBoxes(RectF searchBoxes[]) {
-		mSearchBoxes = searchBoxes;
-		if (mSearchView != null)
-			mSearchView.invalidate();
-	}
-
-	public void setLinkHighlighting(boolean f) {
-		mHighlightLinks = f;
-		if (mSearchView != null)
-			mSearchView.invalidate();
-	}
-
-	public void deselectText() {
-		mSelectBox = null;
-		mSearchView.invalidate();
-	}
-
-	public void selectText(float x0, float y0, float x1, float y1) {
-		float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
-		float docRelX0 = (x0 - getLeft())/scale;
-		float docRelY0 = (y0 - getTop())/scale;
-		float docRelX1 = (x1 - getLeft())/scale;
-		float docRelY1 = (y1 - getTop())/scale;
-		// Order on Y but maintain the point grouping
-		if (docRelY0 <= docRelY1)
-			mSelectBox = new RectF(docRelX0, docRelY0, docRelX1, docRelY1);
-		else
-			mSelectBox = new RectF(docRelX1, docRelY1, docRelX0, docRelY0);
-
-		mSearchView.invalidate();
-
-		if (mGetText == null) {
-			mGetText = new AsyncTask<Void,Void,TextWord[][]>() {
-				@Override
-				protected TextWord[][] doInBackground(Void... params) {
-					return getText();
-				}
-				@Override
-				protected void onPostExecute(TextWord[][] result) {
-					mText = result;
-					mSearchView.invalidate();
-				}
-			};
-
-			mGetText.execute();
-		}
-	}
-
-	public void startDraw(float x, float y) {
-		float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
-		float docRelX = (x - getLeft())/scale;
-		float docRelY = (y - getTop())/scale;
-		if (mDrawing == null)
-			mDrawing = new ArrayList<ArrayList<PointF>>();
-
-		ArrayList<PointF> arc = new ArrayList<PointF>();
-		arc.add(new PointF(docRelX, docRelY));
-		mDrawing.add(arc);
-		mSearchView.invalidate();
-	}
-
-	public void continueDraw(float x, float y) {
-		float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
-		float docRelX = (x - getLeft())/scale;
-		float docRelY = (y - getTop())/scale;
-
-		if (mDrawing != null && mDrawing.size() > 0) {
-			ArrayList<PointF> arc = mDrawing.get(mDrawing.size() - 1);
-			arc.add(new PointF(docRelX, docRelY));
-			mSearchView.invalidate();
-		}
-	}
-
-	public void cancelDraw() {
-		mDrawing = null;
-		mSearchView.invalidate();
-	}
-
-	protected PointF[][] getDraw() {
-		if (mDrawing == null)
-			return null;
-
-		PointF[][] path = new PointF[mDrawing.size()][];
-
-		for (int i = 0; i < mDrawing.size(); i++) {
-			ArrayList<PointF> arc = mDrawing.get(i);
-			path[i] = arc.toArray(new PointF[arc.size()]);
-		}
-
-		return path;
-	}
-
-	protected void processSelectedText(TextProcessor tp) {
-		(new TextSelector(mText, mSelectBox)).select(tp);
-	}
-
-	public void setItemSelectBox(RectF rect) {
-		mItemSelectBox = rect;
-		if (mSearchView != null)
-			mSearchView.invalidate();
-	}
-
-	@Override
-	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-		int x, y;
-		switch(View.MeasureSpec.getMode(widthMeasureSpec)) {
-		case View.MeasureSpec.UNSPECIFIED:
-			x = mSize.x;
-			break;
-		default:
-			x = View.MeasureSpec.getSize(widthMeasureSpec);
-		}
-		switch(View.MeasureSpec.getMode(heightMeasureSpec)) {
-		case View.MeasureSpec.UNSPECIFIED:
-			y = mSize.y;
-			break;
-		default:
-			y = View.MeasureSpec.getSize(heightMeasureSpec);
-		}
-
-		setMeasuredDimension(x, y);
-
-		if (mBusyIndicator != null) {
-			int limit = Math.min(mParentSize.x, mParentSize.y)/2;
-			mBusyIndicator.measure(View.MeasureSpec.AT_MOST | limit, View.MeasureSpec.AT_MOST | limit);
-		}
-	}
-
-	@Override
-	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-		int w  = right-left;
-		int h = bottom-top;
-
-		if (mEntire != null) {
-			if (mEntire.getWidth() != w || mEntire.getHeight() != h) {
-				mEntireMat.setScale(w/(float)mSize.x, h/(float)mSize.y);
-				mEntire.setImageMatrix(mEntireMat);
-				mEntire.invalidate();
-			}
-			mEntire.layout(0, 0, w, h);
-		}
-
-		if (mSearchView != null) {
-			mSearchView.layout(0, 0, w, h);
-		}
-
-		if (mPatchViewSize != null) {
-			if (mPatchViewSize.x != w || mPatchViewSize.y != h) {
-				// Zoomed since patch was created
-				mPatchViewSize = null;
-				mPatchArea     = null;
-				if (mPatch != null) {
-					mPatch.setImageBitmap(null);
-					mPatch.invalidate();
-				}
-			} else {
-				mPatch.layout(mPatchArea.left, mPatchArea.top, mPatchArea.right, mPatchArea.bottom);
-			}
-		}
-
-		if (mBusyIndicator != null) {
-			int bw = mBusyIndicator.getMeasuredWidth();
-			int bh = mBusyIndicator.getMeasuredHeight();
-
-			mBusyIndicator.layout((w-bw)/2, (h-bh)/2, (w+bw)/2, (h+bh)/2);
-		}
-	}
-
-	public void updateHq(boolean update) {
-		Rect viewArea = new Rect(getLeft(),getTop(),getRight(),getBottom());
-		if (viewArea.width() == mSize.x || viewArea.height() == mSize.y) {
-			// If the viewArea's size matches the unzoomed size, there is no need for an hq patch
-			if (mPatch != null) {
-				mPatch.setImageBitmap(null);
-				mPatch.invalidate();
-			}
-		} else {
-			final Point patchViewSize = new Point(viewArea.width(), viewArea.height());
-			final Rect patchArea = new Rect(0, 0, mParentSize.x, mParentSize.y);
-
-			// Intersect and test that there is an intersection
-			if (!patchArea.intersect(viewArea))
-				return;
-
-			// Offset patch area to be relative to the view top left
-			patchArea.offset(-viewArea.left, -viewArea.top);
-
-			boolean area_unchanged = patchArea.equals(mPatchArea) && patchViewSize.equals(mPatchViewSize);
-
-			// If being asked for the same area as last time and not because of an update then nothing to do
-			if (area_unchanged && !update)
-				return;
-
-			boolean completeRedraw = !(area_unchanged && update);
-
-			// Stop the drawing of previous patch if still going
-			if (mDrawPatch != null) {
-				mDrawPatch.cancelAndWait();
-				mDrawPatch = null;
-			}
-
-			// Create and add the image view if not already done
-			if (mPatch == null) {
-				mPatch = new OpaqueImageView(mContext);
-				mPatch.setScaleType(ImageView.ScaleType.MATRIX);
-				addView(mPatch);
-				mSearchView.bringToFront();
-			}
-
-			CancellableTaskDefinition<Void, Void> task;
-
-			if (completeRedraw)
-				task = getDrawPageTask(mPatchBm, patchViewSize.x, patchViewSize.y,
-								patchArea.left, patchArea.top,
-								patchArea.width(), patchArea.height());
-			else
-				task = getUpdatePageTask(mPatchBm, patchViewSize.x, patchViewSize.y,
-						patchArea.left, patchArea.top,
-						patchArea.width(), patchArea.height());
-
-			mDrawPatch = new CancellableAsyncTask<Void,Void>(task) {
-
-				public void onPostExecute(Void result) {
-					mPatchViewSize = patchViewSize;
-					mPatchArea     = patchArea;
-					mPatch.setImageBitmap(mPatchBm);
-					mPatch.invalidate();
-					//requestLayout();
-					// Calling requestLayout here doesn't lead to a later call to layout. No idea
-					// why, but apparently others have run into the problem.
-					mPatch.layout(mPatchArea.left, mPatchArea.top, mPatchArea.right, mPatchArea.bottom);
-				}
-			};
-
-			mDrawPatch.execute();
-		}
-	}
-
-	public void update() {
-		// Cancel pending render task
-		if (mDrawEntire != null) {
-			mDrawEntire.cancelAndWait();
-			mDrawEntire = null;
-		}
-
-		if (mDrawPatch != null) {
-			mDrawPatch.cancelAndWait();
-			mDrawPatch = null;
-		}
-
-
-		// Render the page in the background
-		mDrawEntire = new CancellableAsyncTask<Void, Void>(getUpdatePageTask(mEntireBm, mSize.x, mSize.y, 0, 0, mSize.x, mSize.y)) {
-
-			public void onPostExecute(Void result) {
-				mEntire.setImageBitmap(mEntireBm);
-				mEntire.invalidate();
-			}
-		};
-
-		mDrawEntire.execute();
-
-		updateHq(true);
-	}
-
-	public void removeHq() {
-			// Stop the drawing of the patch if still going
-			if (mDrawPatch != null) {
-				mDrawPatch.cancelAndWait();
-				mDrawPatch = null;
-			}
-
-			// And get rid of it
-			mPatchViewSize = null;
-			mPatchArea = null;
-			if (mPatch != null) {
-				mPatch.setImageBitmap(null);
-				mPatch.invalidate();
-			}
-	}
-
-	public int getPage() {
-		return mPageNumber;
-	}
-
-	@Override
-	public boolean isOpaque() {
-		return true;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/PrintDialogActivity.java b/platform/android/src/com/artifex/mupdfdemo/PrintDialogActivity.java
deleted file mode 100644
index d96322d5..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/PrintDialogActivity.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-
-import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Base64;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-public class PrintDialogActivity extends Activity {
-	private static final String PRINT_DIALOG_URL = "https://www.google.com/cloudprint/dialog.html";
-	private static final String JS_INTERFACE = "AndroidPrintDialog";
-	private static final String CONTENT_TRANSFER_ENCODING = "base64";
-
-	private static final String ZXING_URL = "http://zxing.appspot.com";
-	private static final int ZXING_SCAN_REQUEST = 65743;
-
-	/**
-	 * Post message that is sent by Print Dialog web page when the printing dialog
-	 * needs to be closed.
-	 */
-	private static final String CLOSE_POST_MESSAGE_NAME = "cp-dialog-on-close";
-
-	/**
-	 * Web view element to show the printing dialog in.
-	 */
-	private WebView dialogWebView;
-
-	/**
-	 * Intent that started the action.
-	 */
-	Intent cloudPrintIntent;
-
-	private int resultCode;
-
-	@Override
-	public void onCreate(Bundle icicle) {
-		super.onCreate(icicle);
-
-		resultCode = RESULT_OK;
-		setContentView(R.layout.print_dialog);
-		dialogWebView = (WebView) findViewById(R.id.webview);
-		cloudPrintIntent = this.getIntent();
-
-		WebSettings settings = dialogWebView.getSettings();
-		settings.setJavaScriptEnabled(true);
-
-		dialogWebView.setWebViewClient(new PrintDialogWebClient());
-		dialogWebView.addJavascriptInterface(
-			new PrintDialogJavaScriptInterface(), JS_INTERFACE);
-
-		dialogWebView.loadUrl(PRINT_DIALOG_URL);
-	}
-
-	@Override
-	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
-		if (requestCode == ZXING_SCAN_REQUEST && resultCode == RESULT_OK) {
-			dialogWebView.loadUrl(intent.getStringExtra("SCAN_RESULT"));
-		}
-	}
-
-	final class PrintDialogJavaScriptInterface {
-		public String getType() {
-			return cloudPrintIntent.getType();
-		}
-
-		public String getTitle() {
-			return cloudPrintIntent.getExtras().getString("title");
-		}
-
-		public String getContent() {
-			try {
-				ContentResolver contentResolver = getContentResolver();
-				InputStream is = contentResolver.openInputStream(cloudPrintIntent.getData());
-				ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
-				byte[] buffer = new byte[4096];
-				int n = is.read(buffer);
-				while (n >= 0) {
-					baos.write(buffer, 0, n);
-					n = is.read(buffer);
-				}
-				is.close();
-				baos.flush();
-
-				return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
-			} catch (Throwable e) {
-				resultCode = RESULT_CANCELED;
-				setResult(resultCode);
-				finish();
-				e.printStackTrace();
-			}
-			return "";
-		}
-
-		public String getEncoding() {
-			return CONTENT_TRANSFER_ENCODING;
-		}
-
-		public void onPostMessage(String message) {
-			if (message.startsWith(CLOSE_POST_MESSAGE_NAME)) {
-				setResult(resultCode);
-				finish();
-			}
-		}
-	}
-
-	private final class PrintDialogWebClient extends WebViewClient {
-		@Override
-		public boolean shouldOverrideUrlLoading(WebView view, String url) {
-			if (url.startsWith(ZXING_URL)) {
-				Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
-				intentScan.putExtra("SCAN_MODE", "QR_CODE_MODE");
-				try {
-					startActivityForResult(intentScan, ZXING_SCAN_REQUEST);
-				} catch (ActivityNotFoundException error) {
-					view.loadUrl(url);
-				}
-			} else {
-				view.loadUrl(url);
-			}
-			return false;
-		}
-
-		@Override
-		public void onPageFinished(WebView view, String url) {
-			if (PRINT_DIALOG_URL.equals(url)) {
-				// Submit print document.
-				view.loadUrl("javascript:printDialog.setPrintDocument(printDialog.createPrintDocument("
-					+ "window." + JS_INTERFACE + ".getType(),window." + JS_INTERFACE + ".getTitle(),"
-					+ "window." + JS_INTERFACE + ".getContent(),window." + JS_INTERFACE + ".getEncoding()))");
-
-				// Add post messages listener.
-				view.loadUrl("javascript:window.addEventListener('message',"
-						+ "function(evt){window." + JS_INTERFACE + ".onPostMessage(evt.data)}, false)");
-			}
-		}
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/ReaderView.java b/platform/android/src/com/artifex/mupdfdemo/ReaderView.java
deleted file mode 100644
index 65d8f665..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/ReaderView.java
+++ /dev/null
@@ -1,936 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.View;
-import android.widget.Adapter;
-import android.widget.AdapterView;
-import android.widget.Scroller;
-
-public class ReaderView
-		extends AdapterView<Adapter>
-		implements GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, Runnable {
-	private static final int  MOVING_DIAGONALLY = 0;
-	private static final int  MOVING_LEFT       = 1;
-	private static final int  MOVING_RIGHT      = 2;
-	private static final int  MOVING_UP         = 3;
-	private static final int  MOVING_DOWN       = 4;
-
-	private static final int  FLING_MARGIN      = 100;
-	private static final int  GAP               = 20;
-
-	private static final float MIN_SCALE        = 1.0f;
-	private static final float MAX_SCALE        = 5.0f;
-	private static final float REFLOW_SCALE_FACTOR = 0.5f;
-
-	private static final boolean HORIZONTAL_SCROLLING = true;
-
-	private Adapter           mAdapter;
-	private int               mCurrent;    // Adapter's index for the current view
-	private boolean           mResetLayout;
-	private final SparseArray<View>
-				  mChildViews = new SparseArray<View>(3);
-					       // Shadows the children of the adapter view
-					       // but with more sensible indexing
-	private final LinkedList<View>
-				  mViewCache = new LinkedList<View>();
-	private boolean           mUserInteracting;  // Whether the user is interacting
-	private boolean           mScaling;    // Whether the user is currently pinch zooming
-	private float             mScale     = 1.0f;
-	private int               mXScroll;    // Scroll amounts recorded from events.
-	private int               mYScroll;    // and then accounted for in onLayout
-	private boolean           mReflow = false;
-	private boolean           mReflowChanged = false;
-	private final GestureDetector
-				  mGestureDetector;
-	private final ScaleGestureDetector
-				  mScaleGestureDetector;
-	private final Scroller    mScroller;
-	private final Stepper     mStepper;
-	private int               mScrollerLastX;
-	private int               mScrollerLastY;
-	private float		  mLastScaleFocusX;
-	private float		  mLastScaleFocusY;
-
-	static abstract class ViewMapper {
-		abstract void applyToView(View view);
-	}
-
-	public ReaderView(Context context) {
-		super(context);
-		mGestureDetector = new GestureDetector(this);
-		mScaleGestureDetector = new ScaleGestureDetector(context, this);
-		mScroller        = new Scroller(context);
-		mStepper = new Stepper(this, this);
-	}
-
-	public ReaderView(Context context, AttributeSet attrs) {
-		super(context, attrs);
-		
-		// "Edit mode" means when the View is being displayed in the Android GUI editor. (this class
-		// is instantiated in the IDE, so we need to be a bit careful what we do).
-		if (isInEditMode())
-		{
-			mGestureDetector = null;
-			mScaleGestureDetector = null;
-			mScroller = null;
-			mStepper = null;
-		}
-		else
-		{
-			mGestureDetector = new GestureDetector(this);
-			mScaleGestureDetector = new ScaleGestureDetector(context, this);
-			mScroller        = new Scroller(context);
-			mStepper = new Stepper(this, this);
-		}
-	}
-
-	public ReaderView(Context context, AttributeSet attrs, int defStyle) {
-		super(context, attrs, defStyle);
-		mGestureDetector = new GestureDetector(this);
-		mScaleGestureDetector = new ScaleGestureDetector(context, this);
-		mScroller        = new Scroller(context);
-		mStepper = new Stepper(this, this);
-	}
-
-	public int getDisplayedViewIndex() {
-		return mCurrent;
-	}
-
-	public void setDisplayedViewIndex(int i) {
-		if (0 <= i && i < mAdapter.getCount()) {
-			onMoveOffChild(mCurrent);
-			mCurrent = i;
-			onMoveToChild(i);
-			mResetLayout = true;
-			requestLayout();
-		}
-	}
-
-	public void moveToNext() {
-		View v = mChildViews.get(mCurrent+1);
-		if (v != null)
-			slideViewOntoScreen(v);
-	}
-
-	public void moveToPrevious() {
-		View v = mChildViews.get(mCurrent-1);
-		if (v != null)
-			slideViewOntoScreen(v);
-	}
-
-	// When advancing down the page, we want to advance by about
-	// 90% of a screenful. But we'd be happy to advance by between
-	// 80% and 95% if it means we hit the bottom in a whole number
-	// of steps.
-	private int smartAdvanceAmount(int screenHeight, int max) {
-		int advance = (int)(screenHeight * 0.9 + 0.5);
-		int leftOver = max % advance;
-		int steps = max / advance;
-		if (leftOver == 0) {
-			// We'll make it exactly. No adjustment
-		} else if ((float)leftOver / steps <= screenHeight * 0.05) {
-			// We can adjust up by less than 5% to make it exact.
-			advance += (int)((float)leftOver/steps + 0.5);
-		} else {
-			int overshoot = advance - leftOver;
-			if ((float)overshoot / steps <= screenHeight * 0.1) {
-				// We can adjust down by less than 10% to make it exact.
-				advance -= (int)((float)overshoot/steps + 0.5);
-			}
-		}
-		if (advance > max)
-			advance = max;
-		return advance;
-	}
-
-	public void smartMoveForwards() {
-		View v = mChildViews.get(mCurrent);
-		if (v == null)
-			return;
-
-		// The following code works in terms of where the screen is on the views;
-		// so for example, if the currentView is at (-100,-100), the visible
-		// region would be at (100,100). If the previous page was (2000, 3000) in
-		// size, the visible region of the previous page might be (2100 + GAP, 100)
-		// (i.e. off the previous page). This is different to the way the rest of
-		// the code in this file is written, but it's easier for me to think about.
-		// At some point we may refactor this to fit better with the rest of the
-		// code.
-
-		// screenWidth/Height are the actual width/height of the screen. e.g. 480/800
-		int screenWidth  = getWidth();
-		int screenHeight = getHeight();
-		// We might be mid scroll; we want to calculate where we scroll to based on
-		// where this scroll would end, not where we are now (to allow for people
-		// bashing 'forwards' very fast.
-		int remainingX = mScroller.getFinalX() - mScroller.getCurrX();
-		int remainingY = mScroller.getFinalY() - mScroller.getCurrY();
-		// right/bottom is in terms of pixels within the scaled document; e.g. 1000
-		int top = -(v.getTop()  + mYScroll + remainingY);
-		int right  = screenWidth -(v.getLeft() + mXScroll + remainingX);
-		int bottom = screenHeight+top;
-		// docWidth/Height are the width/height of the scaled document e.g. 2000x3000
-		int docWidth  = v.getMeasuredWidth();
-		int docHeight = v.getMeasuredHeight();
-
-		int xOffset, yOffset;
-		if (bottom >= docHeight) {
-			// We are flush with the bottom. Advance to next column.
-			if (right + screenWidth > docWidth) {
-				// No room for another column - go to next page
-				View nv = mChildViews.get(mCurrent+1);
-				if (nv == null) // No page to advance to
-					return;
-				int nextTop  = -(nv.getTop() + mYScroll + remainingY);
-				int nextLeft = -(nv.getLeft() + mXScroll + remainingX);
-				int nextDocWidth = nv.getMeasuredWidth();
-				int nextDocHeight = nv.getMeasuredHeight();
-
-				// Allow for the next page maybe being shorter than the screen is high
-				yOffset = (nextDocHeight < screenHeight ? ((nextDocHeight - screenHeight)>>1) : 0);
-
-				if (nextDocWidth < screenWidth) {
-					// Next page is too narrow to fill the screen. Scroll to the top, centred.
-					xOffset = (nextDocWidth - screenWidth)>>1;
-				} else {
-					// Reset X back to the left hand column
-					xOffset = right % screenWidth;
-					// Adjust in case the previous page is less wide
-					if (xOffset + screenWidth > nextDocWidth)
-						xOffset = nextDocWidth - screenWidth;
-				}
-				xOffset -= nextLeft;
-				yOffset -= nextTop;
-			} else {
-				// Move to top of next column
-				xOffset = screenWidth;
-				yOffset = screenHeight - bottom;
-			}
-		} else {
-			// Advance by 90% of the screen height downwards (in case lines are partially cut off)
-			xOffset = 0;
-			yOffset = smartAdvanceAmount(screenHeight, docHeight - bottom);
-		}
-		mScrollerLastX = mScrollerLastY = 0;
-		mScroller.startScroll(0, 0, remainingX - xOffset, remainingY - yOffset, 400);
-		mStepper.prod();
-	}
-
-	public void smartMoveBackwards() {
-		View v = mChildViews.get(mCurrent);
-		if (v == null)
-			return;
-
-		// The following code works in terms of where the screen is on the views;
-		// so for example, if the currentView is at (-100,-100), the visible
-		// region would be at (100,100). If the previous page was (2000, 3000) in
-		// size, the visible region of the previous page might be (2100 + GAP, 100)
-		// (i.e. off the previous page). This is different to the way the rest of
-		// the code in this file is written, but it's easier for me to think about.
-		// At some point we may refactor this to fit better with the rest of the
-		// code.
-
-		// screenWidth/Height are the actual width/height of the screen. e.g. 480/800
-		int screenWidth  = getWidth();
-		int screenHeight = getHeight();
-		// We might be mid scroll; we want to calculate where we scroll to based on
-		// where this scroll would end, not where we are now (to allow for people
-		// bashing 'forwards' very fast.
-		int remainingX = mScroller.getFinalX() - mScroller.getCurrX();
-		int remainingY = mScroller.getFinalY() - mScroller.getCurrY();
-		// left/top is in terms of pixels within the scaled document; e.g. 1000
-		int left  = -(v.getLeft() + mXScroll + remainingX);
-		int top   = -(v.getTop()  + mYScroll + remainingY);
-		// docWidth/Height are the width/height of the scaled document e.g. 2000x3000
-		int docHeight = v.getMeasuredHeight();
-
-		int xOffset, yOffset;
-		if (top <= 0) {
-			// We are flush with the top. Step back to previous column.
-			if (left < screenWidth) {
-				/* No room for previous column - go to previous page */
-				View pv = mChildViews.get(mCurrent-1);
-				if (pv == null) /* No page to advance to */
-					return;
-				int prevDocWidth = pv.getMeasuredWidth();
-				int prevDocHeight = pv.getMeasuredHeight();
-
-				// Allow for the next page maybe being shorter than the screen is high
-				yOffset = (prevDocHeight < screenHeight ? ((prevDocHeight - screenHeight)>>1) : 0);
-
-				int prevLeft  = -(pv.getLeft() + mXScroll);
-				int prevTop  = -(pv.getTop() + mYScroll);
-				if (prevDocWidth < screenWidth) {
-					// Previous page is too narrow to fill the screen. Scroll to the bottom, centred.
-					xOffset = (prevDocWidth - screenWidth)>>1;
-				} else {
-					// Reset X back to the right hand column
-					xOffset = (left > 0 ? left % screenWidth : 0);
-					if (xOffset + screenWidth > prevDocWidth)
-						xOffset = prevDocWidth - screenWidth;
-					while (xOffset + screenWidth*2 < prevDocWidth)
-						xOffset += screenWidth;
-				}
-				xOffset -= prevLeft;
-				yOffset -= prevTop-prevDocHeight+screenHeight;
-			} else {
-				// Move to bottom of previous column
-				xOffset = -screenWidth;
-				yOffset = docHeight - screenHeight + top;
-			}
-		} else {
-			// Retreat by 90% of the screen height downwards (in case lines are partially cut off)
-			xOffset = 0;
-			yOffset = -smartAdvanceAmount(screenHeight, top);
-		}
-		mScrollerLastX = mScrollerLastY = 0;
-		mScroller.startScroll(0, 0, remainingX - xOffset, remainingY - yOffset, 400);
-		mStepper.prod();
-	}
-
-	public void resetupChildren() {
-		for (int i = 0; i < mChildViews.size(); i++)
-			onChildSetup(mChildViews.keyAt(i), mChildViews.valueAt(i));
-	}
-
-	public void applyToChildren(ViewMapper mapper) {
-		for (int i = 0; i < mChildViews.size(); i++)
-			mapper.applyToView(mChildViews.valueAt(i));
-	}
-
-	public void refresh(boolean reflow) {
-		mReflow = reflow;
-		mReflowChanged = true;
-		mResetLayout = true;
-
-		mScale = 1.0f;
-		mXScroll = mYScroll = 0;
-
-		requestLayout();
-	}
-
-	protected void onChildSetup(int i, View v) {}
-
-	protected void onMoveToChild(int i) {}
-
-	protected void onMoveOffChild(int i) {}
-
-	protected void onSettle(View v) {};
-
-	protected void onUnsettle(View v) {};
-
-	protected void onNotInUse(View v) {};
-
-	protected void onScaleChild(View v, Float scale) {};
-
-	public View getView(int i) {
-		return mChildViews.get(i);
-	}
-
-	public View getDisplayedView() {
-		return mChildViews.get(mCurrent);
-	}
-
-	public void run() {
-		if (!mScroller.isFinished()) {
-			mScroller.computeScrollOffset();
-			int x = mScroller.getCurrX();
-			int y = mScroller.getCurrY();
-			mXScroll += x - mScrollerLastX;
-			mYScroll += y - mScrollerLastY;
-			mScrollerLastX = x;
-			mScrollerLastY = y;
-			requestLayout();
-			mStepper.prod();
-		}
-		else if (!mUserInteracting) {
-			// End of an inertial scroll and the user is not interacting.
-			// The layout is stable
-			View v = mChildViews.get(mCurrent);
-			if (v != null)
-				postSettle(v);
-		}
-	}
-
-	public boolean onDown(MotionEvent arg0) {
-		mScroller.forceFinished(true);
-		return true;
-	}
-
-	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
-			float velocityY) {
-		if (mScaling)
-			return true;
-
-		View v = mChildViews.get(mCurrent);
-		if (v != null) {
-			Rect bounds = getScrollBounds(v);
-			switch(directionOfTravel(velocityX, velocityY)) {
-			case MOVING_LEFT:
-				if (HORIZONTAL_SCROLLING && bounds.left >= 0) {
-					// Fling off to the left bring next view onto screen
-					View vl = mChildViews.get(mCurrent+1);
-
-					if (vl != null) {
-						slideViewOntoScreen(vl);
-						return true;
-					}
-				}
-				break;
-			case MOVING_UP:
-				if (!HORIZONTAL_SCROLLING && bounds.top >= 0) {
-					// Fling off to the top bring next view onto screen
-					View vl = mChildViews.get(mCurrent+1);
-
-					if (vl != null) {
-						slideViewOntoScreen(vl);
-						return true;
-					}
-				}
-				break;
-			case MOVING_RIGHT:
-				if (HORIZONTAL_SCROLLING && bounds.right <= 0) {
-					// Fling off to the right bring previous view onto screen
-					View vr = mChildViews.get(mCurrent-1);
-
-					if (vr != null) {
-						slideViewOntoScreen(vr);
-						return true;
-					}
-				}
-				break;
-			case MOVING_DOWN:
-				if (!HORIZONTAL_SCROLLING && bounds.bottom <= 0) {
-					// Fling off to the bottom bring previous view onto screen
-					View vr = mChildViews.get(mCurrent-1);
-
-					if (vr != null) {
-						slideViewOntoScreen(vr);
-						return true;
-					}
-				}
-				break;
-			}
-			mScrollerLastX = mScrollerLastY = 0;
-			// If the page has been dragged out of bounds then we want to spring back
-			// nicely. fling jumps back into bounds instantly, so we don't want to use
-			// fling in that case. On the other hand, we don't want to forgo a fling
-			// just because of a slightly off-angle drag taking us out of bounds other
-			// than in the direction of the drag, so we test for out of bounds only
-			// in the direction of travel.
-			//
-			// Also don't fling if out of bounds in any direction by more than fling
-			// margin
-			Rect expandedBounds = new Rect(bounds);
-			expandedBounds.inset(-FLING_MARGIN, -FLING_MARGIN);
-
-			if(withinBoundsInDirectionOfTravel(bounds, velocityX, velocityY)
-					&& expandedBounds.contains(0, 0)) {
-				mScroller.fling(0, 0, (int)velocityX, (int)velocityY, bounds.left, bounds.right, bounds.top, bounds.bottom);
-				mStepper.prod();
-			}
-		}
-
-		return true;
-	}
-
-	public void onLongPress(MotionEvent e) {
-	}
-
-	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
-			float distanceY) {
-		if (!mScaling) {
-			mXScroll -= distanceX;
-			mYScroll -= distanceY;
-			requestLayout();
-		}
-		return true;
-	}
-
-	public void onShowPress(MotionEvent e) {
-	}
-
-	public boolean onSingleTapUp(MotionEvent e) {
-		return false;
-	}
-
-	public boolean onScale(ScaleGestureDetector detector) {
-		float previousScale = mScale;
-		float scale_factor = mReflow ? REFLOW_SCALE_FACTOR : 1.0f;
-		float min_scale = MIN_SCALE * scale_factor;
-		float max_scale = MAX_SCALE * scale_factor;
-		mScale = Math.min(Math.max(mScale * detector.getScaleFactor(), min_scale), max_scale);
-
-		if (mReflow) {
-			View v = mChildViews.get(mCurrent);
-			if (v != null)
-				onScaleChild(v, mScale);
-		} else {
-			float factor = mScale/previousScale;
-
-			View v = mChildViews.get(mCurrent);
-			if (v != null) {
-				float currentFocusX = detector.getFocusX();
-				float currentFocusY = detector.getFocusY();
-				// Work out the focus point relative to the view top left
-				int viewFocusX = (int)currentFocusX - (v.getLeft() + mXScroll);
-				int viewFocusY = (int)currentFocusY - (v.getTop() + mYScroll);
-				// Scroll to maintain the focus point
-				mXScroll += viewFocusX - viewFocusX * factor;
-				mYScroll += viewFocusY - viewFocusY * factor;
-
-				if (mLastScaleFocusX>=0)
-					mXScroll+=currentFocusX-mLastScaleFocusX;
-				if (mLastScaleFocusY>=0)
-					mYScroll+=currentFocusY-mLastScaleFocusY;
-
-				mLastScaleFocusX=currentFocusX;
-				mLastScaleFocusY=currentFocusY;
-				requestLayout();
-			}
-		}
-		return true;
-	}
-
-	public boolean onScaleBegin(ScaleGestureDetector detector) {
-		mScaling = true;
-		// Ignore any scroll amounts yet to be accounted for: the
-		// screen is not showing the effect of them, so they can
-		// only confuse the user
-		mXScroll = mYScroll = 0;
-		mLastScaleFocusX = mLastScaleFocusY = -1;
-		return true;
-	}
-
-	public void onScaleEnd(ScaleGestureDetector detector) {
-		if (mReflow) {
-			applyToChildren(new ViewMapper() {
-				@Override
-				void applyToView(View view) {
-					onScaleChild(view, mScale);
-				}
-			});
-		}
-		mScaling = false;
-	}
-
-	@Override
-	public boolean onTouchEvent(MotionEvent event) {
-		mScaleGestureDetector.onTouchEvent(event);
-		mGestureDetector.onTouchEvent(event);
-
-		if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
-			mUserInteracting = true;
-		}
-		if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
-			mUserInteracting = false;
-
-			View v = mChildViews.get(mCurrent);
-			if (v != null) {
-				if (mScroller.isFinished()) {
-					// If, at the end of user interaction, there is no
-					// current inertial scroll in operation then animate
-					// the view onto screen if necessary
-					slideViewOntoScreen(v);
-				}
-
-				if (mScroller.isFinished()) {
-					// If still there is no inertial scroll in operation
-					// then the layout is stable
-					postSettle(v);
-				}
-			}
-		}
-
-		requestLayout();
-		return true;
-	}
-
-	@Override
-	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-		int n = getChildCount();
-		for (int i = 0; i < n; i++)
-			measureView(getChildAt(i));
-	}
-
-	@Override
-	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-		super.onLayout(changed, left, top, right, bottom);
-
-		try {
-			onLayout2(changed, left, top, right, bottom);
-		}
-		catch (java.lang.OutOfMemoryError e) {
-			System.out.println("Out of memory during layout");
-
-			//  we might get an out of memory error.
-			//  so let's display an alert.
-			//  TODO: a better message, in resources.
-
-			if (!memAlert) {
-				memAlert = true;
-				AlertDialog alertDialog = MuPDFActivity.getAlertBuilder().create();
-				alertDialog.setMessage("Out of memory during layout");
-				alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
-					new DialogInterface.OnClickListener() {
-						public void onClick(DialogInterface dialog, int which) {
-							dialog.dismiss();
-							memAlert = false;
-						}
-					});
-				alertDialog.show();
-			}
-		}
-	}
-
-	private boolean memAlert = false;
-
-	private void onLayout2(boolean changed, int left, int top, int right,
-			int bottom) {
-
-		// "Edit mode" means when the View is being displayed in the Android GUI editor. (this class
-		// is instantiated in the IDE, so we need to be a bit careful what we do).
-		if (isInEditMode())
-			return;
-
-		View cv = mChildViews.get(mCurrent);
-		Point cvOffset;
-
-		if (!mResetLayout) {
-			// Move to next or previous if current is sufficiently off center
-			if (cv != null) {
-				boolean move;
-				cvOffset = subScreenSizeOffset(cv);
-				// cv.getRight() may be out of date with the current scale
-				// so add left to the measured width for the correct position
-				if (HORIZONTAL_SCROLLING)
-					move = cv.getLeft() + cv.getMeasuredWidth() + cvOffset.x + GAP/2 + mXScroll < getWidth()/2;
-				else
-					move = cv.getTop() + cv.getMeasuredHeight() + cvOffset.y + GAP/2 + mYScroll < getHeight()/2;
-				if (move && mCurrent + 1 < mAdapter.getCount()) {
-					postUnsettle(cv);
-					// post to invoke test for end of animation
-					// where we must set hq area for the new current view
-					mStepper.prod();
-
-					onMoveOffChild(mCurrent);
-					mCurrent++;
-					onMoveToChild(mCurrent);
-				}
-
-				if (HORIZONTAL_SCROLLING)
-					move = cv.getLeft() - cvOffset.x - GAP/2 + mXScroll >= getWidth()/2;
-				else
-					move = cv.getTop() - cvOffset.y - GAP/2 + mYScroll >= getHeight()/2;
-				if (move && mCurrent > 0) {
-					postUnsettle(cv);
-					// post to invoke test for end of animation
-					// where we must set hq area for the new current view
-					mStepper.prod();
-
-					onMoveOffChild(mCurrent);
-					mCurrent--;
-					onMoveToChild(mCurrent);
-				}
-			}
-
-			// Remove not needed children and hold them for reuse
-			int numChildren = mChildViews.size();
-			int childIndices[] = new int[numChildren];
-			for (int i = 0; i < numChildren; i++)
-				childIndices[i] = mChildViews.keyAt(i);
-
-			for (int i = 0; i < numChildren; i++) {
-				int ai = childIndices[i];
-				if (ai < mCurrent - 1 || ai > mCurrent + 1) {
-					View v = mChildViews.get(ai);
-					onNotInUse(v);
-					mViewCache.add(v);
-					removeViewInLayout(v);
-					mChildViews.remove(ai);
-				}
-			}
-		} else {
-			mResetLayout = false;
-			mXScroll = mYScroll = 0;
-
-			// Remove all children and hold them for reuse
-			int numChildren = mChildViews.size();
-			for (int i = 0; i < numChildren; i++) {
-				View v = mChildViews.valueAt(i);
-				onNotInUse(v);
-				mViewCache.add(v);
-				removeViewInLayout(v);
-			}
-			mChildViews.clear();
-
-			// Don't reuse cached views if the adapter has changed
-			if (mReflowChanged) {
-				mReflowChanged = false;
-				mViewCache.clear();
-			}
-
-			// post to ensure generation of hq area
-			mStepper.prod();
-		}
-
-		// Ensure current view is present
-		int cvLeft, cvRight, cvTop, cvBottom;
-		boolean notPresent = (mChildViews.get(mCurrent) == null);
-		cv = getOrCreateChild(mCurrent);
-		// When the view is sub-screen-size in either dimension we
-		// offset it to center within the screen area, and to keep
-		// the views spaced out
-		cvOffset = subScreenSizeOffset(cv);
-		if (notPresent) {
-			//Main item not already present. Just place it top left
-			cvLeft = cvOffset.x;
-			cvTop  = cvOffset.y;
-		} else {
-			// Main item already present. Adjust by scroll offsets
-			cvLeft = cv.getLeft() + mXScroll;
-			cvTop  = cv.getTop()  + mYScroll;
-		}
-		// Scroll values have been accounted for
-		mXScroll = mYScroll = 0;
-		cvRight  = cvLeft + cv.getMeasuredWidth();
-		cvBottom = cvTop  + cv.getMeasuredHeight();
-
-		if (!mUserInteracting && mScroller.isFinished()) {
-			Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom));
-			cvRight  += corr.x;
-			cvLeft   += corr.x;
-			cvTop    += corr.y;
-			cvBottom += corr.y;
-		} else if (HORIZONTAL_SCROLLING && cv.getMeasuredHeight() <= getHeight()) {
-			// When the current view is as small as the screen in height, clamp
-			// it vertically
-			Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom));
-			cvTop    += corr.y;
-			cvBottom += corr.y;
-		} else if (!HORIZONTAL_SCROLLING && cv.getMeasuredWidth() <= getWidth()) {
-			// When the current view is as small as the screen in width, clamp
-			// it horizontally
-			Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom));
-			cvRight  += corr.x;
-			cvLeft   += corr.x;
-		}
-
-		cv.layout(cvLeft, cvTop, cvRight, cvBottom);
-
-		if (mCurrent > 0) {
-			View lv = getOrCreateChild(mCurrent - 1);
-			Point leftOffset = subScreenSizeOffset(lv);
-			if (HORIZONTAL_SCROLLING)
-			{
-				int gap = leftOffset.x + GAP + cvOffset.x;
-				lv.layout(cvLeft - lv.getMeasuredWidth() - gap,
-						(cvBottom + cvTop - lv.getMeasuredHeight())/2,
-						cvLeft - gap,
-						(cvBottom + cvTop + lv.getMeasuredHeight())/2);
-			} else {
-				int gap = leftOffset.y + GAP + cvOffset.y;
-				lv.layout((cvLeft + cvRight - lv.getMeasuredWidth())/2,
-						cvTop - lv.getMeasuredHeight() - gap,
-						(cvLeft + cvRight + lv.getMeasuredWidth())/2,
-						cvTop - gap);
-			}
-		}
-
-		if (mCurrent + 1 < mAdapter.getCount()) {
-			View rv = getOrCreateChild(mCurrent + 1);
-			Point rightOffset = subScreenSizeOffset(rv);
-			if (HORIZONTAL_SCROLLING)
-			{
-				int gap = cvOffset.x + GAP + rightOffset.x;
-				rv.layout(cvRight + gap,
-						(cvBottom + cvTop - rv.getMeasuredHeight())/2,
-						cvRight + rv.getMeasuredWidth() + gap,
-						(cvBottom + cvTop + rv.getMeasuredHeight())/2);
-			} else {
-				int gap = cvOffset.y + GAP + rightOffset.y;
-				rv.layout((cvLeft + cvRight - rv.getMeasuredWidth())/2,
-						cvBottom + gap,
-						(cvLeft + cvRight + rv.getMeasuredWidth())/2,
-						cvBottom + gap + rv.getMeasuredHeight());
-			}
-		}
-
-		invalidate();
-	}
-
-	@Override
-	public Adapter getAdapter() {
-		return mAdapter;
-	}
-
-	@Override
-	public View getSelectedView() {
-		return null;
-	}
-
-	@Override
-	public void setAdapter(Adapter adapter) {
-
-		//  release previous adapter's bitmaps
-		if (null!=mAdapter && adapter!=mAdapter) {
-			if (adapter instanceof MuPDFPageAdapter){
-				((MuPDFPageAdapter) adapter).releaseBitmaps();
-			}
-		}
-
-		mAdapter = adapter;
-
-		requestLayout();
-	}
-
-	@Override
-	public void setSelection(int arg0) {
-		throw new UnsupportedOperationException(getContext().getString(R.string.not_supported));
-	}
-
-	private View getCached() {
-		if (mViewCache.size() == 0)
-			return null;
-		else
-			return mViewCache.removeFirst();
-	}
-
-	private View getOrCreateChild(int i) {
-		View v = mChildViews.get(i);
-		if (v == null) {
-			v = mAdapter.getView(i, getCached(), this);
-			addAndMeasureChild(i, v);
-			onChildSetup(i, v);
-			onScaleChild(v, mScale);
-		}
-
-		return v;
-	}
-
-	private void addAndMeasureChild(int i, View v) {
-		LayoutParams params = v.getLayoutParams();
-		if (params == null) {
-			params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-		}
-		addViewInLayout(v, 0, params, true);
-		mChildViews.append(i, v); // Record the view against it's adapter index
-		measureView(v);
-	}
-
-	private void measureView(View v) {
-		// See what size the view wants to be
-		v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-
-		if (!mReflow) {
-		// Work out a scale that will fit it to this view
-		float scale = Math.min((float)getWidth()/(float)v.getMeasuredWidth(),
-					(float)getHeight()/(float)v.getMeasuredHeight());
-		// Use the fitting values scaled by our current scale factor
-		v.measure(View.MeasureSpec.EXACTLY | (int)(v.getMeasuredWidth()*scale*mScale),
-				View.MeasureSpec.EXACTLY | (int)(v.getMeasuredHeight()*scale*mScale));
-		} else {
-			v.measure(View.MeasureSpec.EXACTLY | (int)(v.getMeasuredWidth()),
-					View.MeasureSpec.EXACTLY | (int)(v.getMeasuredHeight()));
-		}
-	}
-
-	private Rect getScrollBounds(int left, int top, int right, int bottom) {
-		int xmin = getWidth() - right;
-		int xmax = -left;
-		int ymin = getHeight() - bottom;
-		int ymax = -top;
-
-		// In either dimension, if view smaller than screen then
-		// constrain it to be central
-		if (xmin > xmax) xmin = xmax = (xmin + xmax)/2;
-		if (ymin > ymax) ymin = ymax = (ymin + ymax)/2;
-
-		return new Rect(xmin, ymin, xmax, ymax);
-	}
-
-	private Rect getScrollBounds(View v) {
-		// There can be scroll amounts not yet accounted for in
-		// onLayout, so add mXScroll and mYScroll to the current
-		// positions when calculating the bounds.
-		return getScrollBounds(v.getLeft() + mXScroll,
-				               v.getTop() + mYScroll,
-				               v.getLeft() + v.getMeasuredWidth() + mXScroll,
-				               v.getTop() + v.getMeasuredHeight() + mYScroll);
-	}
-
-	private Point getCorrection(Rect bounds) {
-		return new Point(Math.min(Math.max(0,bounds.left),bounds.right),
-				         Math.min(Math.max(0,bounds.top),bounds.bottom));
-	}
-
-	private void postSettle(final View v) {
-		// onSettle and onUnsettle are posted so that the calls
-		// wont be executed until after the system has performed
-		// layout.
-		post (new Runnable() {
-			public void run () {
-				onSettle(v);
-			}
-		});
-	}
-
-	private void postUnsettle(final View v) {
-		post (new Runnable() {
-			public void run () {
-				onUnsettle(v);
-			}
-		});
-	}
-
-	private void slideViewOntoScreen(View v) {
-		Point corr = getCorrection(getScrollBounds(v));
-		if (corr.x != 0 || corr.y != 0) {
-			mScrollerLastX = mScrollerLastY = 0;
-			mScroller.startScroll(0, 0, corr.x, corr.y, 400);
-			mStepper.prod();
-		}
-	}
-
-	private Point subScreenSizeOffset(View v) {
-		return new Point(Math.max((getWidth() - v.getMeasuredWidth())/2, 0),
-				Math.max((getHeight() - v.getMeasuredHeight())/2, 0));
-	}
-
-	private static int directionOfTravel(float vx, float vy) {
-		if (Math.abs(vx) > 2 * Math.abs(vy))
-			return (vx > 0) ? MOVING_RIGHT : MOVING_LEFT;
-		else if (Math.abs(vy) > 2 * Math.abs(vx))
-			return (vy > 0) ? MOVING_DOWN : MOVING_UP;
-		else
-			return MOVING_DIAGONALLY;
-	}
-
-	private static boolean withinBoundsInDirectionOfTravel(Rect bounds, float vx, float vy) {
-		switch (directionOfTravel(vx, vy)) {
-		case MOVING_DIAGONALLY: return bounds.contains(0, 0);
-		case MOVING_LEFT:       return bounds.left <= 0;
-		case MOVING_RIGHT:      return bounds.right >= 0;
-		case MOVING_UP:         return bounds.top <= 0;
-		case MOVING_DOWN:       return bounds.bottom >= 0;
-		default: throw new NoSuchElementException();
-		}
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/SafeAnimatorInflater.java b/platform/android/src/com/artifex/mupdfdemo/SafeAnimatorInflater.java
deleted file mode 100644
index 7f715bb4..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/SafeAnimatorInflater.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
-import android.app.Activity;
-import android.view.View;
-
-public class SafeAnimatorInflater
-{
-	private View mView;
-
-	public SafeAnimatorInflater(Activity activity, int animation, View view)
-	{
-		AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(activity, R.animator.info);
-		mView = view;
-		set.setTarget(view);
-		set.addListener(new Animator.AnimatorListener() {
-			public void onAnimationStart(Animator animation) {
-				mView.setVisibility(View.VISIBLE);
-			}
-
-			public void onAnimationRepeat(Animator animation) {
-			}
-
-			public void onAnimationEnd(Animator animation) {
-				mView.setVisibility(View.INVISIBLE);
-			}
-
-			public void onAnimationCancel(Animator animation) {
-			}
-		});
-		set.start();
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/SearchTask.java b/platform/android/src/com/artifex/mupdfdemo/SearchTask.java
deleted file mode 100644
index d3969f10..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/SearchTask.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.graphics.RectF;
-import android.os.Handler;
-
-class ProgressDialogX extends ProgressDialog {
-	public ProgressDialogX(Context context) {
-		super(context);
-	}
-
-	private boolean mCancelled = false;
-
-	public boolean isCancelled() {
-		return mCancelled;
-	}
-
-	@Override
-	public void cancel() {
-		mCancelled = true;
-		super.cancel();
-	}
-}
-
-public abstract class SearchTask {
-	private static final int SEARCH_PROGRESS_DELAY = 200;
-	private final Context mContext;
-	private final MuPDFCore mCore;
-	private final Handler mHandler;
-	private final AlertDialog.Builder mAlertBuilder;
-	private AsyncTask<Void,Integer,SearchTaskResult> mSearchTask;
-
-	public SearchTask(Context context, MuPDFCore core) {
-		mContext = context;
-		mCore = core;
-		mHandler = new Handler();
-		mAlertBuilder = new AlertDialog.Builder(context);
-	}
-
-	protected abstract void onTextFound(SearchTaskResult result);
-
-	public void stop() {
-		if (mSearchTask != null) {
-			mSearchTask.cancel(true);
-			mSearchTask = null;
-		}
-	}
-
-	public void go(final String text, int direction, int displayPage, int searchPage) {
-		if (mCore == null)
-			return;
-		stop();
-
-		final int increment = direction;
-		final int startIndex = searchPage == -1 ? displayPage : searchPage + increment;
-
-		final ProgressDialogX progressDialog = new ProgressDialogX(mContext);
-		progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
-		progressDialog.setTitle(mContext.getString(R.string.searching_));
-		progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-			public void onCancel(DialogInterface dialog) {
-				stop();
-			}
-		});
-		progressDialog.setMax(mCore.countPages());
-
-		mSearchTask = new AsyncTask<Void,Integer,SearchTaskResult>() {
-			@Override
-			protected SearchTaskResult doInBackground(Void... params) {
-				int index = startIndex;
-
-				while (0 <= index && index < mCore.countPages() && !isCancelled()) {
-					publishProgress(index);
-					RectF searchHits[] = mCore.searchPage(index, text);
-
-					if (searchHits != null && searchHits.length > 0)
-						return new SearchTaskResult(text, index, searchHits);
-
-					index += increment;
-				}
-				return null;
-			}
-
-			@Override
-			protected void onPostExecute(SearchTaskResult result) {
-				progressDialog.cancel();
-				if (result != null) {
-				    onTextFound(result);
-				} else {
-					mAlertBuilder.setTitle(SearchTaskResult.get() == null ? R.string.text_not_found : R.string.no_further_occurrences_found);
-					AlertDialog alert = mAlertBuilder.create();
-					alert.setButton(AlertDialog.BUTTON_POSITIVE, mContext.getString(R.string.dismiss),
-							(DialogInterface.OnClickListener)null);
-					alert.show();
-				}
-			}
-
-			@Override
-			protected void onCancelled() {
-				progressDialog.cancel();
-			}
-
-			@Override
-			protected void onProgressUpdate(Integer... values) {
-				progressDialog.setProgress(values[0].intValue());
-			}
-
-			@Override
-			protected void onPreExecute() {
-				super.onPreExecute();
-				mHandler.postDelayed(new Runnable() {
-					public void run() {
-						if (!progressDialog.isCancelled())
-						{
-							progressDialog.show();
-							progressDialog.setProgress(startIndex);
-						}
-					}
-				}, SEARCH_PROGRESS_DELAY);
-			}
-		};
-
-		mSearchTask.execute();
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/SearchTaskResult.java b/platform/android/src/com/artifex/mupdfdemo/SearchTaskResult.java
deleted file mode 100644
index 8fa3c3a2..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/SearchTaskResult.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.graphics.RectF;
-
-public class SearchTaskResult {
-	public final String txt;
-	public final int   pageNumber;
-	public final RectF searchBoxes[];
-	static private SearchTaskResult singleton;
-
-	SearchTaskResult(String _txt, int _pageNumber, RectF _searchBoxes[]) {
-		txt = _txt;
-		pageNumber = _pageNumber;
-		searchBoxes = _searchBoxes;
-	}
-
-	static public SearchTaskResult get() {
-		return singleton;
-	}
-
-	static public void set(SearchTaskResult r) {
-		singleton = r;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/Separation.java b/platform/android/src/com/artifex/mupdfdemo/Separation.java
deleted file mode 100644
index eadda4ba..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/Separation.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public class Separation
-{
-	String name;
-	int rgba;
-	int cmyk;
-
-	public Separation(String name, int rgba, int cmyk)
-	{
-		this.name = name;
-		this.rgba = rgba;
-		this.cmyk = cmyk;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/Stepper.java b/platform/android/src/com/artifex/mupdfdemo/Stepper.java
deleted file mode 100644
index d22240ef..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/Stepper.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.annotation.SuppressLint;
-import android.os.Build;
-import android.view.View;
-
-public class Stepper {
-	protected final View mPoster;
-	protected final Runnable mTask;
-	protected boolean mPending;
-
-	public Stepper(View v, Runnable r) {
-		mPoster = v;
-		mTask = r;
-		mPending = false;
-	}
-
-	@SuppressLint("NewApi")
-	public void prod() {
-		if (!mPending) {
-			mPending = true;
-			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-				mPoster.postOnAnimation(new Runnable() {
-					@Override
-					public void run() {
-						mPending = false;
-						mTask.run();
-					}
-				});
-			} else {
-				mPoster.post(new Runnable() {
-					@Override
-					public void run() {
-						mPending = false;
-						mTask.run();
-					}
-				});
-
-			}
-		}
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/TextChar.java b/platform/android/src/com/artifex/mupdfdemo/TextChar.java
deleted file mode 100644
index aebf519f..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/TextChar.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.graphics.RectF;
-
-public class TextChar extends RectF {
-	public char c;
-
-	public TextChar(float x0, float y0, float x1, float y1, char _c) {
-		super(x0, y0, x1, y1);
-		c = _c;
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/TextWord.java b/platform/android/src/com/artifex/mupdfdemo/TextWord.java
deleted file mode 100644
index d9672573..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/TextWord.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import android.graphics.RectF;
-
-public class TextWord extends RectF {
-	public String w;
-
-	public TextWord() {
-		super();
-		w = new String();
-	}
-
-	public void Add(TextChar tc) {
-		super.union(tc);
-		w = w.concat(new String(new char[]{tc.c}));
-	}
-}
diff --git a/platform/android/src/com/artifex/mupdfdemo/WidgetType.java b/platform/android/src/com/artifex/mupdfdemo/WidgetType.java
deleted file mode 100644
index 882a38f2..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/WidgetType.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.artifex.mupdfdemo;
-
-public enum WidgetType {
-	NONE,
-	TEXT,
-	LISTBOX,
-	COMBOBOX,
-	SIGNATURE
-}
-- 
cgit v1.2.3