diff options
Diffstat (limited to 'platform/android/viewer/src/com/artifex')
11 files changed, 1817 insertions, 1817 deletions
diff --git a/platform/android/viewer/src/com/artifex/mupdfdemo/ArrayDeque.java b/platform/android/viewer/src/com/artifex/mupdfdemo/ArrayDeque.java index 4f06ea41..c8549058 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/ArrayDeque.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/ArrayDeque.java @@ -62,794 +62,794 @@ import java.util.Stack; * @param <E> the type of elements held in this collection */ public class ArrayDeque<E> extends AbstractCollection<E> - implements Deque<E>, Cloneable, java.io.Serializable + 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(); - } + /** + * 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/viewer/src/com/artifex/mupdfdemo/AsyncTask.java b/platform/android/viewer/src/com/artifex/mupdfdemo/AsyncTask.java index b370794c..f2dcf70a 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/AsyncTask.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/AsyncTask.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -67,25 +67,25 @@ import android.os.Message; * <p>Here is an example of subclassing:</p> * <pre class="prettyprint"> * private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { - * 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 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 onProgressUpdate(Integer... progress) { + * setProgressPercent(progress[0]); + * } * - * protected void onPostExecute(Long result) { - * showDialog("Downloaded " + result + " bytes"); - * } + * protected void onPostExecute(Long result) { + * showDialog("Downloaded " + result + " bytes"); + * } * } * </pre> * @@ -97,12 +97,12 @@ import android.os.Message; * <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> + * <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> @@ -113,25 +113,25 @@ import android.os.Message; * <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> + * <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> @@ -147,24 +147,24 @@ import android.os.Message; * <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> + * <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}. + * <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> @@ -178,493 +178,493 @@ import android.os.Message; * {@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; - } - } + 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/viewer/src/com/artifex/mupdfdemo/Deque.java b/platform/android/viewer/src/com/artifex/mupdfdemo/Deque.java index ad17bcc0..97aefeab 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/Deque.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/Deque.java @@ -41,37 +41,37 @@ import java.util.Stack; * <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> + * <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> + * <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> + * <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> + * <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> + * <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> * @@ -84,32 +84,32 @@ import java.util.Stack; * <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> + * <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> + * <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> + * <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> + * <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> + * <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> + * <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> + * <td>{@link java.util.Queue#peek peek()}</td> + * <td>{@link #peek peekFirst()}</td> * </tr> * </table> * @@ -122,20 +122,20 @@ import java.util.Stack; * <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> + * <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> + * <td>{@link #push push(e)}</td> + * <td>{@link #addFirst addFirst(e)}</td> * </tr> * <tr> - * <td>{@link #pop pop()}</td> - * <td>{@link #removeFirst removeFirst()}</td> + * <td>{@link #pop pop()}</td> + * <td>{@link #removeFirst removeFirst()}</td> * </tr> * <tr> - * <td>{@link #peek peek()}</td> - * <td>{@link #peekFirst peekFirst()}</td> + * <td>{@link #peek peek()}</td> + * <td>{@link #peekFirst peekFirst()}</td> * </tr> * </table> * @@ -170,383 +170,383 @@ import java.util.Stack; */ 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 ? e==null : 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 ? e==null : 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 ? e==null : 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 ? e==null : 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(); + /** + * 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 ? e==null : 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 ? e==null : 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 ? e==null : 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 ? e==null : 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/viewer/src/com/artifex/mupdfdemo/MuPDFActivity.java b/platform/android/viewer/src/com/artifex/mupdfdemo/MuPDFActivity.java index 91b1e8fe..08d32be9 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/MuPDFActivity.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/MuPDFActivity.java @@ -274,7 +274,7 @@ public class MuPDFActivity extends Activity implements FilePicker.FilePickerSupp super.onCreate(savedInstanceState); mAlertBuilder = new AlertDialog.Builder(this); - gAlertBuilder = mAlertBuilder; // keep a static copy of this that other classes can use + gAlertBuilder = mAlertBuilder; // keep a static copy of this that other classes can use if (core == null) { core = (MuPDFCore)getLastNonConfigurationInstance(); diff --git a/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineActivityData.java b/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineActivityData.java index a703e61e..be1386e6 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineActivityData.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineActivityData.java @@ -2,7 +2,7 @@ package com.artifex.mupdfdemo; public class OutlineActivityData { public OutlineItem items[]; - public int position; + public int position; static private OutlineActivityData singleton; static public void set(OutlineActivityData d) { diff --git a/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineAdapter.java b/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineAdapter.java index 4251ed8e..c1b22021 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineAdapter.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineAdapter.java @@ -7,11 +7,11 @@ import android.widget.BaseAdapter; import android.widget.TextView; public class OutlineAdapter extends BaseAdapter { - private final OutlineItem mItems[]; + private final OutlineItem mItems[]; private final LayoutInflater mInflater; public OutlineAdapter(LayoutInflater inflater, OutlineItem items[]) { mInflater = inflater; - mItems = items; + mItems = items; } public int getCount() { diff --git a/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineItem.java b/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineItem.java index 7730991e..0ed041c2 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineItem.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/OutlineItem.java @@ -1,14 +1,14 @@ package com.artifex.mupdfdemo; public class OutlineItem { - public final int level; + public final int level; public final String title; - public final int page; + public final int page; OutlineItem(int _level, String _title, int _page) { level = _level; title = _title; - page = _page; + page = _page; } } diff --git a/platform/android/viewer/src/com/artifex/mupdfdemo/PageView.java b/platform/android/viewer/src/com/artifex/mupdfdemo/PageView.java index c897f414..502e0c2b 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/PageView.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/PageView.java @@ -94,7 +94,7 @@ public abstract class PageView extends ViewGroup { 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 final Context mContext; protected int mPageNumber; private Point mParentSize; protected Point mSize; // Size of page at minimum zoom @@ -127,7 +127,7 @@ public abstract class PageView extends ViewGroup { public PageView(Context c, Point parentSize, Bitmap sharedHqBm) { super(c); - mContext = c; + mContext = c; mParentSize = parentSize; setBackgroundColor(BACKGROUND_COLOR); mEntireBm = Bitmap.createBitmap(parentSize.x, parentSize.y, Config.ARGB_8888); @@ -201,7 +201,7 @@ public abstract class PageView extends ViewGroup { public void releaseBitmaps() { reinit(); - // recycle bitmaps before releasing them. + // recycle bitmaps before releasing them. if (mEntireBm!=null) mEntireBm.recycle(); @@ -320,16 +320,16 @@ public abstract class PageView extends ViewGroup { paint.setColor(HIGHLIGHT_COLOR); for (RectF rect : mSearchBoxes) canvas.drawRect(rect.left*scale, rect.top*scale, - rect.right*scale, rect.bottom*scale, - paint); + 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); + link.rect.right*scale, link.rect.bottom*scale, + paint); } if (mSelectBox != null && mText != null) { @@ -536,7 +536,7 @@ public abstract class PageView extends ViewGroup { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int w = right-left; + int w = right-left; int h = bottom-top; if (mEntire != null) { @@ -556,7 +556,7 @@ public abstract class PageView extends ViewGroup { if (mPatchViewSize.x != w || mPatchViewSize.y != h) { // Zoomed since patch was created mPatchViewSize = null; - mPatchArea = null; + mPatchArea = null; if (mPatch != null) { mPatch.setImageBitmap(null); mPatch.invalidate(); @@ -630,7 +630,7 @@ public abstract class PageView extends ViewGroup { public void onPostExecute(Void result) { mPatchViewSize = patchViewSize; - mPatchArea = patchArea; + mPatchArea = patchArea; mPatch.setImageBitmap(mPatchBm); mPatch.invalidate(); //requestLayout(); diff --git a/platform/android/viewer/src/com/artifex/mupdfdemo/ReaderView.java b/platform/android/viewer/src/com/artifex/mupdfdemo/ReaderView.java index f91efa41..bfccdb19 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/ReaderView.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/ReaderView.java @@ -24,14 +24,14 @@ 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 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 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; @@ -74,7 +74,7 @@ public class ReaderView super(context); mGestureDetector = new GestureDetector(this); mScaleGestureDetector = new ScaleGestureDetector(context, this); - mScroller = new Scroller(context); + mScroller = new Scroller(context); mStepper = new Stepper(this, this); } @@ -94,7 +94,7 @@ public class ReaderView { mGestureDetector = new GestureDetector(this); mScaleGestureDetector = new ScaleGestureDetector(context, this); - mScroller = new Scroller(context); + mScroller = new Scroller(context); mStepper = new Stepper(this, this); } } @@ -103,7 +103,7 @@ public class ReaderView super(context, attrs, defStyle); mGestureDetector = new GestureDetector(this); mScaleGestureDetector = new ScaleGestureDetector(context, this); - mScroller = new Scroller(context); + mScroller = new Scroller(context); mStepper = new Stepper(this, this); } @@ -173,7 +173,7 @@ public class ReaderView // code. // screenWidth/Height are the actual width/height of the screen. e.g. 480/800 - int screenWidth = getWidth(); + 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 @@ -181,11 +181,11 @@ public class ReaderView 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 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 docWidth = v.getMeasuredWidth(); int docHeight = v.getMeasuredHeight(); int xOffset, yOffset; @@ -196,7 +196,7 @@ public class ReaderView View nv = mChildViews.get(mCurrent+1); if (nv == null) // No page to advance to return; - int nextTop = -(nv.getTop() + mYScroll + remainingY); + int nextTop = -(nv.getTop() + mYScroll + remainingY); int nextLeft = -(nv.getLeft() + mXScroll + remainingX); int nextDocWidth = nv.getMeasuredWidth(); int nextDocHeight = nv.getMeasuredHeight(); @@ -246,7 +246,7 @@ public class ReaderView // code. // screenWidth/Height are the actual width/height of the screen. e.g. 480/800 - int screenWidth = getWidth(); + 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 @@ -254,8 +254,8 @@ public class ReaderView 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); + 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(); @@ -273,8 +273,8 @@ public class ReaderView // 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); + 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; @@ -580,9 +580,9 @@ public class ReaderView 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. + // we might get an out of memory error. + // so let's display an alert. + // TODO: a better message, in resources. if (!memAlert) { memAlert = true; @@ -700,37 +700,37 @@ public class ReaderView // the views spaced out cvOffset = subScreenSizeOffset(cv); if (notPresent) { - //Main item not already present. Just place it top left + // Main item not already present. Just place it top left cvLeft = cvOffset.x; - cvTop = cvOffset.y; + cvTop = cvOffset.y; } else { // Main item already present. Adjust by scroll offsets cvLeft = cv.getLeft() + mXScroll; - cvTop = cv.getTop() + mYScroll; + cvTop = cv.getTop() + mYScroll; } // Scroll values have been accounted for mXScroll = mYScroll = 0; - cvRight = cvLeft + cv.getMeasuredWidth(); - cvBottom = cvTop + cv.getMeasuredHeight(); + 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; + 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; + 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; + cvRight += corr.x; + cvLeft += corr.x; } cv.layout(cvLeft, cvTop, cvRight, cvBottom); @@ -871,14 +871,14 @@ public class ReaderView // 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); + 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)); + Math.min(Math.max(0,bounds.top),bounds.bottom)); } private void postSettle(final View v) { @@ -926,10 +926,10 @@ public class ReaderView 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; + 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/viewer/src/com/artifex/mupdfdemo/SearchTask.java b/platform/android/viewer/src/com/artifex/mupdfdemo/SearchTask.java index d3969f10..7e15f98d 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/SearchTask.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/SearchTask.java @@ -88,7 +88,7 @@ public abstract class SearchTask { protected void onPostExecute(SearchTaskResult result) { progressDialog.cancel(); if (result != null) { - onTextFound(result); + onTextFound(result); } else { mAlertBuilder.setTitle(SearchTaskResult.get() == null ? R.string.text_not_found : R.string.no_further_occurrences_found); AlertDialog alert = mAlertBuilder.create(); diff --git a/platform/android/viewer/src/com/artifex/mupdfdemo/SearchTaskResult.java b/platform/android/viewer/src/com/artifex/mupdfdemo/SearchTaskResult.java index 8fa3c3a2..6c337fe2 100644 --- a/platform/android/viewer/src/com/artifex/mupdfdemo/SearchTaskResult.java +++ b/platform/android/viewer/src/com/artifex/mupdfdemo/SearchTaskResult.java @@ -4,7 +4,7 @@ import android.graphics.RectF; public class SearchTaskResult { public final String txt; - public final int pageNumber; + public final int pageNumber; public final RectF searchBoxes[]; static private SearchTaskResult singleton; |