Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
eaa32c4060
19 changed files with 6780 additions and 50 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2012 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.googlecode.concurrentlinkedhashmap;
|
||||
|
||||
/**
|
||||
* A class that can determine the weight of an entry. The total weight threshold
|
||||
* is used to determine when an eviction is required.
|
||||
*
|
||||
* @author ben.manes@gmail.com (Ben Manes)
|
||||
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
|
||||
* http://code.google.com/p/concurrentlinkedhashmap/</a>
|
||||
*/
|
||||
public interface EntryWeigher<K, V> {
|
||||
|
||||
/**
|
||||
* Measures an entry's weight to determine how many units of capacity that
|
||||
* the key and value consumes. An entry must consume a minimum of one unit.
|
||||
*
|
||||
* @param key the key to weigh
|
||||
* @param value the value to weigh
|
||||
* @return the entry's weight
|
||||
*/
|
||||
int weightOf(K key, V value);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2010 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.googlecode.concurrentlinkedhashmap;
|
||||
|
||||
/**
|
||||
* A listener registered for notification when an entry is evicted. An instance
|
||||
* may be called concurrently by multiple threads to process entries. An
|
||||
* implementation should avoid performing blocking calls or synchronizing on
|
||||
* shared resources.
|
||||
* <p>
|
||||
* The listener is invoked by {@link ConcurrentLinkedHashMap} on a caller's
|
||||
* thread and will not block other threads from operating on the map. An
|
||||
* implementation should be aware that the caller's thread will not expect
|
||||
* long execution times or failures as a side effect of the listener being
|
||||
* notified. Execution safety and a fast turn around time can be achieved by
|
||||
* performing the operation asynchronously, such as by submitting a task to an
|
||||
* {@link java.util.concurrent.ExecutorService}.
|
||||
*
|
||||
* @author ben.manes@gmail.com (Ben Manes)
|
||||
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
|
||||
* http://code.google.com/p/concurrentlinkedhashmap/</a>
|
||||
*/
|
||||
public interface EvictionListener<K, V> {
|
||||
|
||||
/**
|
||||
* A call-back notification that the entry was evicted.
|
||||
*
|
||||
* @param key the entry's key
|
||||
* @param value the entry's value
|
||||
*/
|
||||
void onEviction(K key, V value);
|
||||
}
|
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.googlecode.concurrentlinkedhashmap;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Linked list implementation of the {@link Deque} interface where the link
|
||||
* pointers are tightly integrated with the element. Linked deques have no
|
||||
* capacity restrictions; they grow as necessary to support usage. They are not
|
||||
* thread-safe; in the absence of external synchronization, they do not support
|
||||
* concurrent access by multiple threads. Null elements are prohibited.
|
||||
* <p>
|
||||
* Most <tt>LinkedDeque</tt> operations run in constant time by assuming that
|
||||
* the {@link Linked} parameter is associated with the deque instance. Any usage
|
||||
* that violates this assumption will result in non-deterministic behavior.
|
||||
* <p>
|
||||
* The iterators returned by this class are <em>not</em> <i>fail-fast</i>: If
|
||||
* the deque is modified at any time after the iterator is created, the iterator
|
||||
* will be in an unknown state. Thus, in the face of concurrent modification,
|
||||
* the iterator risks arbitrary, non-deterministic behavior at an undetermined
|
||||
* time in the future.
|
||||
*
|
||||
* @author ben.manes@gmail.com (Ben Manes)
|
||||
* @param <E> the type of elements held in this collection
|
||||
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
|
||||
* http://code.google.com/p/concurrentlinkedhashmap/</a>
|
||||
*/
|
||||
final class LinkedDeque<E extends Linked<E>> extends AbstractCollection<E> implements Deque<E> {
|
||||
|
||||
// This class provides a doubly-linked list that is optimized for the virtual
|
||||
// machine. The first and last elements are manipulated instead of a slightly
|
||||
// more convenient sentinel element to avoid the insertion of null checks with
|
||||
// NullPointerException throws in the byte code. The links to a removed
|
||||
// element are cleared to help a generational garbage collector if the
|
||||
// discarded elements inhabit more than one generation.
|
||||
|
||||
/**
|
||||
* Pointer to first node.
|
||||
* Invariant: (first == null && last == null) ||
|
||||
* (first.prev == null)
|
||||
*/
|
||||
E first;
|
||||
|
||||
/**
|
||||
* Pointer to last node.
|
||||
* Invariant: (first == null && last == null) ||
|
||||
* (last.next == null)
|
||||
*/
|
||||
E last;
|
||||
|
||||
/**
|
||||
* Links the element to the front of the deque so that it becomes the first
|
||||
* element.
|
||||
*
|
||||
* @param e the unlinked element
|
||||
*/
|
||||
void linkFirst(final E e) {
|
||||
final E f = first;
|
||||
first = e;
|
||||
|
||||
if (f == null) {
|
||||
last = e;
|
||||
} else {
|
||||
f.setPrevious(e);
|
||||
e.setNext(f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Links the element to the back of the deque so that it becomes the last
|
||||
* element.
|
||||
*
|
||||
* @param e the unlinked element
|
||||
*/
|
||||
void linkLast(final E e) {
|
||||
final E l = last;
|
||||
last = e;
|
||||
|
||||
if (l == null) {
|
||||
first = e;
|
||||
} else {
|
||||
l.setNext(e);
|
||||
e.setPrevious(l);
|
||||
}
|
||||
}
|
||||
|
||||
/** Unlinks the non-null first element. */
|
||||
E unlinkFirst() {
|
||||
final E f = first;
|
||||
final E next = f.getNext();
|
||||
f.setNext(null);
|
||||
|
||||
first = next;
|
||||
if (next == null) {
|
||||
last = null;
|
||||
} else {
|
||||
next.setPrevious(null);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/** Unlinks the non-null last element. */
|
||||
E unlinkLast() {
|
||||
final E l = last;
|
||||
final E prev = l.getPrevious();
|
||||
l.setPrevious(null);
|
||||
last = prev;
|
||||
if (prev == null) {
|
||||
first = null;
|
||||
} else {
|
||||
prev.setNext(null);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/** Unlinks the non-null element. */
|
||||
void unlink(E e) {
|
||||
final E prev = e.getPrevious();
|
||||
final E next = e.getNext();
|
||||
|
||||
if (prev == null) {
|
||||
first = next;
|
||||
} else {
|
||||
prev.setNext(next);
|
||||
e.setPrevious(null);
|
||||
}
|
||||
|
||||
if (next == null) {
|
||||
last = prev;
|
||||
} else {
|
||||
next.setPrevious(prev);
|
||||
e.setNext(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return (first == null);
|
||||
}
|
||||
|
||||
void checkNotEmpty() {
|
||||
if (isEmpty()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Beware that, unlike in most collections, this method is <em>NOT</em> a
|
||||
* constant-time operation.
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
int size = 0;
|
||||
for (E e = first; e != null; e = e.getNext()) {
|
||||
size++;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
for (E e = first; e != null;) {
|
||||
E next = e.getNext();
|
||||
e.setPrevious(null);
|
||||
e.setNext(null);
|
||||
e = next;
|
||||
}
|
||||
first = last = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return (o instanceof Linked<?>) && contains((Linked<?>) o);
|
||||
}
|
||||
|
||||
// A fast-path containment check
|
||||
boolean contains(Linked<?> e) {
|
||||
return (e.getPrevious() != null)
|
||||
|| (e.getNext() != null)
|
||||
|| (e == first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the element to the front of the deque so that it becomes the first
|
||||
* element.
|
||||
*
|
||||
* @param e the linked element
|
||||
*/
|
||||
public void moveToFront(E e) {
|
||||
if (e != first) {
|
||||
unlink(e);
|
||||
linkFirst(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the element to the back of the deque so that it becomes the last
|
||||
* element.
|
||||
*
|
||||
* @param e the linked element
|
||||
*/
|
||||
public void moveToBack(E e) {
|
||||
if (e != last) {
|
||||
unlink(e);
|
||||
linkLast(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peek() {
|
||||
return peekFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peekFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peekLast() {
|
||||
return last;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getFirst() {
|
||||
checkNotEmpty();
|
||||
return peekFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getLast() {
|
||||
checkNotEmpty();
|
||||
return peekLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E element() {
|
||||
return getFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(E e) {
|
||||
return offerLast(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offerFirst(E e) {
|
||||
if (contains(e)) {
|
||||
return false;
|
||||
}
|
||||
linkFirst(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offerLast(E e) {
|
||||
if (contains(e)) {
|
||||
return false;
|
||||
}
|
||||
linkLast(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
return offerLast(e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addFirst(E e) {
|
||||
if (!offerFirst(e)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLast(E e) {
|
||||
if (!offerLast(e)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E poll() {
|
||||
return pollFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pollFirst() {
|
||||
return isEmpty() ? null : unlinkFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pollLast() {
|
||||
return isEmpty() ? null : unlinkLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove() {
|
||||
return removeFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean remove(Object o) {
|
||||
return (o instanceof Linked<?>) && remove((E) o);
|
||||
}
|
||||
|
||||
// A fast-path removal
|
||||
boolean remove(E e) {
|
||||
if (contains(e)) {
|
||||
unlink(e);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeFirst() {
|
||||
checkNotEmpty();
|
||||
return pollFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeFirstOccurrence(Object o) {
|
||||
return remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeLast() {
|
||||
checkNotEmpty();
|
||||
return pollLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeLastOccurrence(Object o) {
|
||||
return remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
boolean modified = false;
|
||||
for (Object o : c) {
|
||||
modified |= remove(o);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(E e) {
|
||||
addFirst(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pop() {
|
||||
return removeFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new AbstractLinkedIterator(first) {
|
||||
@Override E computeNext() {
|
||||
return cursor.getNext();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> descendingIterator() {
|
||||
return new AbstractLinkedIterator(last) {
|
||||
@Override E computeNext() {
|
||||
return cursor.getPrevious();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
abstract class AbstractLinkedIterator implements Iterator<E> {
|
||||
E cursor;
|
||||
|
||||
/**
|
||||
* Creates an iterator that can can traverse the deque.
|
||||
*
|
||||
* @param start the initial element to begin traversal from
|
||||
*/
|
||||
AbstractLinkedIterator(E start) {
|
||||
cursor = start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (cursor != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
E e = cursor;
|
||||
cursor = computeNext();
|
||||
return e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next element to traverse to or <tt>null</tt> if there are
|
||||
* no more elements.
|
||||
*/
|
||||
abstract E computeNext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An element that is linked on the {@link Deque}.
|
||||
*/
|
||||
interface Linked<T extends Linked<T>> {
|
||||
|
||||
/**
|
||||
* Retrieves the previous element or <tt>null</tt> if either the element is
|
||||
* unlinked or the first element on the deque.
|
||||
*/
|
||||
T getPrevious();
|
||||
|
||||
/** Sets the previous element or <tt>null</tt> if there is no link. */
|
||||
void setPrevious(T prev);
|
||||
|
||||
/**
|
||||
* Retrieves the next element or <tt>null</tt> if either the element is
|
||||
* unlinked or the last element on the deque.
|
||||
*/
|
||||
T getNext();
|
||||
|
||||
/** Sets the next element or <tt>null</tt> if there is no link. */
|
||||
void setNext(T next);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2010 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.googlecode.concurrentlinkedhashmap;
|
||||
|
||||
/**
|
||||
* A class that can determine the weight of a value. The total weight threshold
|
||||
* is used to determine when an eviction is required.
|
||||
*
|
||||
* @author ben.manes@gmail.com (Ben Manes)
|
||||
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
|
||||
* http://code.google.com/p/concurrentlinkedhashmap/</a>
|
||||
*/
|
||||
public interface Weigher<V> {
|
||||
|
||||
/**
|
||||
* Measures an object's weight to determine how many units of capacity that
|
||||
* the value consumes. A value must consume a minimum of one unit.
|
||||
*
|
||||
* @param value the object to weigh
|
||||
* @return the object's weight
|
||||
*/
|
||||
int weightOf(V value);
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Copyright 2010 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.googlecode.concurrentlinkedhashmap;
|
||||
|
||||
import static com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A common set of {@link Weigher} and {@link EntryWeigher} implementations.
|
||||
*
|
||||
* @author ben.manes@gmail.com (Ben Manes)
|
||||
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
|
||||
* http://code.google.com/p/concurrentlinkedhashmap/</a>
|
||||
*/
|
||||
public final class Weighers {
|
||||
|
||||
private Weighers() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* A entry weigher backed by the specified weigher. The weight of the value
|
||||
* determines the weight of the entry.
|
||||
*
|
||||
* @param weigher the weigher to be "wrapped" in a entry weigher.
|
||||
* @return A entry weigher view of the specified weigher.
|
||||
*/
|
||||
public static <K, V> EntryWeigher<K, V> asEntryWeigher(
|
||||
final Weigher<? super V> weigher) {
|
||||
return (weigher == singleton())
|
||||
? Weighers.<K, V>entrySingleton()
|
||||
: new EntryWeigherView<K, V>(weigher);
|
||||
}
|
||||
|
||||
/**
|
||||
* A weigher where an entry has a weight of <tt>1</tt>. A map bounded with
|
||||
* this weigher will evict when the number of key-value pairs exceeds the
|
||||
* capacity.
|
||||
*
|
||||
* @return A weigher where a value takes one unit of capacity.
|
||||
*/
|
||||
@SuppressWarnings({"cast", "unchecked"})
|
||||
public static <K, V> EntryWeigher<K, V> entrySingleton() {
|
||||
return (EntryWeigher<K, V>) SingletonEntryWeigher.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A weigher where a value has a weight of <tt>1</tt>. A map bounded with
|
||||
* this weigher will evict when the number of key-value pairs exceeds the
|
||||
* capacity.
|
||||
*
|
||||
* @return A weigher where a value takes one unit of capacity.
|
||||
*/
|
||||
@SuppressWarnings({"cast", "unchecked"})
|
||||
public static <V> Weigher<V> singleton() {
|
||||
return (Weigher<V>) SingletonWeigher.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A weigher where the value is a byte array and its weight is the number of
|
||||
* bytes. A map bounded with this weigher will evict when the number of bytes
|
||||
* exceeds the capacity rather than the number of key-value pairs in the map.
|
||||
* This allows for restricting the capacity based on the memory-consumption
|
||||
* and is primarily for usage by dedicated caching servers that hold the
|
||||
* serialized data.
|
||||
* <p>
|
||||
* A value with a weight of <tt>0</tt> will be rejected by the map. If a value
|
||||
* with this weight can occur then the caller should eagerly evaluate the
|
||||
* value and treat it as a removal operation. Alternatively, a custom weigher
|
||||
* may be specified on the map to assign an empty value a positive weight.
|
||||
*
|
||||
* @return A weigher where each byte takes one unit of capacity.
|
||||
*/
|
||||
public static Weigher<byte[]> byteArray() {
|
||||
return ByteArrayWeigher.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A weigher where the value is a {@link Iterable} and its weight is the
|
||||
* number of elements. This weigher only should be used when the alternative
|
||||
* {@link #collection()} weigher cannot be, as evaluation takes O(n) time. A
|
||||
* map bounded with this weigher will evict when the total number of elements
|
||||
* exceeds the capacity rather than the number of key-value pairs in the map.
|
||||
* <p>
|
||||
* A value with a weight of <tt>0</tt> will be rejected by the map. If a value
|
||||
* with this weight can occur then the caller should eagerly evaluate the
|
||||
* value and treat it as a removal operation. Alternatively, a custom weigher
|
||||
* may be specified on the map to assign an empty value a positive weight.
|
||||
*
|
||||
* @return A weigher where each element takes one unit of capacity.
|
||||
*/
|
||||
@SuppressWarnings({"cast", "unchecked"})
|
||||
public static <E> Weigher<? super Iterable<E>> iterable() {
|
||||
return (Weigher<Iterable<E>>) (Weigher<?>) IterableWeigher.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A weigher where the value is a {@link Collection} and its weight is the
|
||||
* number of elements. A map bounded with this weigher will evict when the
|
||||
* total number of elements exceeds the capacity rather than the number of
|
||||
* key-value pairs in the map.
|
||||
* <p>
|
||||
* A value with a weight of <tt>0</tt> will be rejected by the map. If a value
|
||||
* with this weight can occur then the caller should eagerly evaluate the
|
||||
* value and treat it as a removal operation. Alternatively, a custom weigher
|
||||
* may be specified on the map to assign an empty value a positive weight.
|
||||
*
|
||||
* @return A weigher where each element takes one unit of capacity.
|
||||
*/
|
||||
@SuppressWarnings({"cast", "unchecked"})
|
||||
public static <E> Weigher<? super Collection<E>> collection() {
|
||||
return (Weigher<Collection<E>>) (Weigher<?>) CollectionWeigher.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A weigher where the value is a {@link List} and its weight is the number
|
||||
* of elements. A map bounded with this weigher will evict when the total
|
||||
* number of elements exceeds the capacity rather than the number of
|
||||
* key-value pairs in the map.
|
||||
* <p>
|
||||
* A value with a weight of <tt>0</tt> will be rejected by the map. If a value
|
||||
* with this weight can occur then the caller should eagerly evaluate the
|
||||
* value and treat it as a removal operation. Alternatively, a custom weigher
|
||||
* may be specified on the map to assign an empty value a positive weight.
|
||||
*
|
||||
* @return A weigher where each element takes one unit of capacity.
|
||||
*/
|
||||
@SuppressWarnings({"cast", "unchecked"})
|
||||
public static <E> Weigher<? super List<E>> list() {
|
||||
return (Weigher<List<E>>) (Weigher<?>) ListWeigher.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A weigher where the value is a {@link Set} and its weight is the number
|
||||
* of elements. A map bounded with this weigher will evict when the total
|
||||
* number of elements exceeds the capacity rather than the number of
|
||||
* key-value pairs in the map.
|
||||
* <p>
|
||||
* A value with a weight of <tt>0</tt> will be rejected by the map. If a value
|
||||
* with this weight can occur then the caller should eagerly evaluate the
|
||||
* value and treat it as a removal operation. Alternatively, a custom weigher
|
||||
* may be specified on the map to assign an empty value a positive weight.
|
||||
*
|
||||
* @return A weigher where each element takes one unit of capacity.
|
||||
*/
|
||||
@SuppressWarnings({"cast", "unchecked"})
|
||||
public static <E> Weigher<? super Set<E>> set() {
|
||||
return (Weigher<Set<E>>) (Weigher<?>) SetWeigher.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A weigher where the value is a {@link Map} and its weight is the number of
|
||||
* entries. A map bounded with this weigher will evict when the total number of
|
||||
* entries across all values exceeds the capacity rather than the number of
|
||||
* key-value pairs in the map.
|
||||
* <p>
|
||||
* A value with a weight of <tt>0</tt> will be rejected by the map. If a value
|
||||
* with this weight can occur then the caller should eagerly evaluate the
|
||||
* value and treat it as a removal operation. Alternatively, a custom weigher
|
||||
* may be specified on the map to assign an empty value a positive weight.
|
||||
*
|
||||
* @return A weigher where each entry takes one unit of capacity.
|
||||
*/
|
||||
@SuppressWarnings({"cast", "unchecked"})
|
||||
public static <A, B> Weigher<? super Map<A, B>> map() {
|
||||
return (Weigher<Map<A, B>>) (Weigher<?>) MapWeigher.INSTANCE;
|
||||
}
|
||||
|
||||
static final class EntryWeigherView<K, V> implements EntryWeigher<K, V>, Serializable {
|
||||
static final long serialVersionUID = 1;
|
||||
final Weigher<? super V> weigher;
|
||||
|
||||
EntryWeigherView(Weigher<? super V> weigher) {
|
||||
checkNotNull(weigher);
|
||||
this.weigher = weigher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int weightOf(K key, V value) {
|
||||
return weigher.weightOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
enum SingletonEntryWeigher implements EntryWeigher<Object, Object> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public int weightOf(Object key, Object value) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
enum SingletonWeigher implements Weigher<Object> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public int weightOf(Object value) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
enum ByteArrayWeigher implements Weigher<byte[]> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public int weightOf(byte[] value) {
|
||||
return value.length;
|
||||
}
|
||||
}
|
||||
|
||||
enum IterableWeigher implements Weigher<Iterable<?>> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public int weightOf(Iterable<?> values) {
|
||||
if (values instanceof Collection<?>) {
|
||||
return ((Collection<?>) values).size();
|
||||
}
|
||||
int size = 0;
|
||||
for (Iterator<?> i = values.iterator(); i.hasNext();) {
|
||||
i.next();
|
||||
size++;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
enum CollectionWeigher implements Weigher<Collection<?>> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public int weightOf(Collection<?> values) {
|
||||
return values.size();
|
||||
}
|
||||
}
|
||||
|
||||
enum ListWeigher implements Weigher<List<?>> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public int weightOf(List<?> values) {
|
||||
return values.size();
|
||||
}
|
||||
}
|
||||
|
||||
enum SetWeigher implements Weigher<Set<?>> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public int weightOf(Set<?> values) {
|
||||
return values.size();
|
||||
}
|
||||
}
|
||||
|
||||
enum MapWeigher implements Weigher<Map<?, ?>> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public int weightOf(Map<?, ?> values) {
|
||||
return values.size();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains an implementation of a bounded
|
||||
* {@link java.util.concurrent.ConcurrentMap} data structure.
|
||||
* <p>
|
||||
* {@link com.googlecode.concurrentlinkedhashmap.Weigher} is a simple interface
|
||||
* for determining how many units of capacity an entry consumes. Depending on
|
||||
* which concrete Weigher class is used, an entry may consume a different amount
|
||||
* of space within the cache. The
|
||||
* {@link com.googlecode.concurrentlinkedhashmap.Weighers} class provides
|
||||
* utility methods for obtaining the most common kinds of implementations.
|
||||
* <p>
|
||||
* {@link com.googlecode.concurrentlinkedhashmap.EvictionListener} provides the
|
||||
* ability to be notified when an entry is evicted from the map. An eviction
|
||||
* occurs when the entry was automatically removed due to the map exceeding a
|
||||
* capacity threshold. It is not called when an entry was explicitly removed.
|
||||
* <p>
|
||||
* The {@link com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap}
|
||||
* class supplies an efficient, scalable, thread-safe, bounded map. As with the
|
||||
* <tt>Java Collections Framework</tt> the "Concurrent" prefix is used to
|
||||
* indicate that the map is not governed by a single exclusion lock.
|
||||
*
|
||||
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
|
||||
* http://code.google.com/p/concurrentlinkedhashmap/</a>
|
||||
*/
|
||||
package com.googlecode.concurrentlinkedhashmap;
|
|
@ -68,6 +68,7 @@
|
|||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -2011,4 +2011,5 @@ Afghanistan, Albania, Algeria, Andorra, Angola, Anguilla, Antigua and Barbuda, A
|
|||
<string name="activate_srtm_plugin">Please activate SRTM plugin</string>
|
||||
<string name="later">Later</string>
|
||||
<string name="get_full_version">Get full version</string>
|
||||
<string name="downloads">Downloads</string>
|
||||
</resources>
|
||||
|
|
|
@ -35,6 +35,8 @@ import android.widget.ArrayAdapter;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IProgress;
|
||||
import net.osmand.IndexConstants;
|
||||
|
@ -77,7 +79,6 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -129,18 +130,22 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
public final OsmandPreference<Boolean> SHOW_RECORDINGS;
|
||||
|
||||
private DataTileManager<Recording> recordings = new DataTileManager<AudioVideoNotesPlugin.Recording>(14);
|
||||
private Map<String, Recording> recordingByFileName = new LinkedHashMap<String, Recording>();
|
||||
private Map<String, Recording> recordingByFileName =
|
||||
new ConcurrentLinkedHashMap.Builder<String, Recording>()
|
||||
.maximumWeightedCapacity(1000)
|
||||
.build();
|
||||
private AudioNotesLayer audioNotesLayer;
|
||||
private MapActivity activity;
|
||||
private MediaRecorder mediaRec;
|
||||
private File lastTakingPhoto;
|
||||
|
||||
private final static char SPLIT_DESC = ' ';
|
||||
private final static char SPLIT_DESC = ' ';
|
||||
|
||||
public static class Recording {
|
||||
public Recording(File f) {
|
||||
this.file = f;
|
||||
}
|
||||
|
||||
|
||||
private File file;
|
||||
|
||||
private double lat;
|
||||
|
@ -177,7 +182,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean setName(String name) {
|
||||
File directory = file.getParentFile();
|
||||
|
@ -193,24 +198,24 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
public String getFileName() {
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
|
||||
public String getDescriptionName(String fileName) {
|
||||
int hashInd = fileName.lastIndexOf(SPLIT_DESC);
|
||||
//backward compatibility
|
||||
if( fileName.indexOf('.') - fileName.indexOf('_') > 12 &&
|
||||
if (fileName.indexOf('.') - fileName.indexOf('_') > 12 &&
|
||||
hashInd < fileName.indexOf('_')) {
|
||||
hashInd = fileName.indexOf('_');
|
||||
}
|
||||
if(hashInd == -1) {
|
||||
if (hashInd == -1) {
|
||||
return null;
|
||||
} else {
|
||||
return fileName.substring(0, hashInd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getOtherName(String fileName) {
|
||||
String descriptionName = getDescriptionName(fileName);
|
||||
if(descriptionName != null) {
|
||||
if (descriptionName != null) {
|
||||
return fileName.substring(descriptionName.length() + 1); // SPLIT_DESC
|
||||
} else {
|
||||
return fileName;
|
||||
|
@ -232,8 +237,8 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
return "";
|
||||
}
|
||||
|
||||
public String getSearchHistoryType(){
|
||||
if (isPhoto()){
|
||||
public String getSearchHistoryType() {
|
||||
if (isPhoto()) {
|
||||
return PointDescription.POINT_TYPE_PHOTO_NOTE;
|
||||
} else if (isVideo()) {
|
||||
return PointDescription.POINT_TYPE_VIDEO_NOTE;
|
||||
|
@ -349,7 +354,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
return ctx.getString(R.string.recording_description, "", getDuration(ctx), time)
|
||||
.trim();
|
||||
}
|
||||
|
||||
|
||||
public String getSmallDescription(Context ctx) {
|
||||
String time = AndroidUtils.formatDateTime(ctx, file.lastModified());
|
||||
if (isPhoto()) {
|
||||
|
@ -357,7 +362,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
}
|
||||
updateInternalDescription();
|
||||
return time + " " + getDuration(ctx);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String getDuration(Context ctx) {
|
||||
|
@ -444,7 +449,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
}
|
||||
audioNotesLayer = new AudioNotesLayer(activity, this);
|
||||
activity.getMapView().addLayer(audioNotesLayer, 3.5f);
|
||||
if(recordControl == null) {
|
||||
if (recordControl == null) {
|
||||
registerWidget(activity);
|
||||
}
|
||||
}
|
||||
|
@ -534,7 +539,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
} else if (audioNotesLayer != null) {
|
||||
mapView.removeLayer(audioNotesLayer);
|
||||
}
|
||||
if(recordControl == null) {
|
||||
if (recordControl == null) {
|
||||
registerWidget(activity);
|
||||
}
|
||||
} else {
|
||||
|
@ -543,7 +548,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
audioNotesLayer = null;
|
||||
}
|
||||
MapInfoLayer mapInfoLayer = activity.getMapLayers().getMapInfoLayer();
|
||||
if(recordControl != null && mapInfoLayer != null) {
|
||||
if (recordControl != null && mapInfoLayer != null) {
|
||||
mapInfoLayer.removeSideWidget(recordControl);
|
||||
recordControl = null;
|
||||
mapInfoLayer.recreateControls();
|
||||
|
@ -1290,7 +1295,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getLogoResourceId() {
|
||||
return R.drawable.ic_action_micro_dark;
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.content.ActivityNotFoundException;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
@ -14,16 +15,18 @@ import android.support.annotation.NonNull;
|
|||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
@ -109,8 +112,10 @@ public class DownloadActivity extends BaseDownloadActivity implements RegionDial
|
|||
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
|
||||
PagerSlidingTabStrip mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.sliding_tabs);
|
||||
|
||||
mTabs.add(new TabActivity.TabItem(R.string.download_tab_local,
|
||||
getString(R.string.download_tab_local), LocalIndexesFragment.class));
|
||||
mTabs.add(new TabActivity.TabItem(R.string.download_tab_downloads,
|
||||
getString(R.string.download_tab_downloads), WorldItemsFragment.class));
|
||||
// mTabs.add(new TabActivity.TabItem(R.string.download_tab_local,
|
||||
// getString(R.string.download_tab_local), LocalIndexesFragment.class));
|
||||
mTabs.add(new TabActivity.TabItem(R.string.download_tab_downloads,
|
||||
getString(R.string.download_tab_downloads), DownloadIndexFragment.class));
|
||||
mTabs.add(new TabActivity.TabItem(R.string.download_tab_updates,
|
||||
|
@ -118,8 +123,6 @@ public class DownloadActivity extends BaseDownloadActivity implements RegionDial
|
|||
|
||||
// mTabs.add(new TabActivity.TabItem(R.string.download_tab_local,
|
||||
// getString(R.string.download_tab_local), NewLocalIndexesFragment.class));
|
||||
mTabs.add(new TabActivity.TabItem(R.string.download_tab_downloads,
|
||||
getString(R.string.download_tab_downloads), WorldItemsFragment.class));
|
||||
|
||||
viewPager.setAdapter(new TabActivity.OsmandFragmentPagerAdapter(getSupportFragmentManager(), mTabs));
|
||||
mSlidingTabLayout.setViewPager(viewPager);
|
||||
|
@ -200,7 +203,7 @@ public class DownloadActivity extends BaseDownloadActivity implements RegionDial
|
|||
protected void onResume() {
|
||||
super.onResume();
|
||||
getMyApplication().getAppCustomization().resumeActivity(DownloadActivity.class, this);
|
||||
initFreeVersionBanner(findViewById(R.id.mainLayout));
|
||||
registerFreeVersionBanner(findViewById(R.id.mainLayout));
|
||||
}
|
||||
|
||||
|
||||
|
@ -571,19 +574,18 @@ public class DownloadActivity extends BaseDownloadActivity implements RegionDial
|
|||
}
|
||||
|
||||
|
||||
public void initFreeVersionBanner(View view) {
|
||||
public void registerFreeVersionBanner(View view) {
|
||||
visibleBanner = new BannerAndDownloadFreeVersion(view, this);
|
||||
updateProgress(true);
|
||||
}
|
||||
|
||||
|
||||
public void showDialog(FragmentActivity activity, DialogFragment fragment) {
|
||||
fragment.show(activity.getSupportFragmentManager(), "dialog");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogDismissed() {
|
||||
initFreeVersionBanner(findViewById(R.id.mainLayout));
|
||||
registerFreeVersionBanner(findViewById(R.id.mainLayout));
|
||||
}
|
||||
|
||||
private static class ToggleCollapseFreeVersionBanner implements View.OnClickListener {
|
||||
|
@ -623,12 +625,12 @@ public class DownloadActivity extends BaseDownloadActivity implements RegionDial
|
|||
private final TextView downloadsLeftTextView;
|
||||
private final View laterButton;
|
||||
|
||||
private final Context ctx;
|
||||
private final FragmentActivity ctx;
|
||||
private final OsmandApplication application;
|
||||
private final boolean shouldShowFreeVersionBanner;
|
||||
private final View freeVersionBannerTitle;
|
||||
|
||||
public BannerAndDownloadFreeVersion(View view, Context ctx) {
|
||||
public BannerAndDownloadFreeVersion(View view, final FragmentActivity ctx) {
|
||||
this.ctx = ctx;
|
||||
application = (OsmandApplication) ctx.getApplicationContext();
|
||||
freeVersionBanner = view.findViewById(R.id.freeVersionBanner);
|
||||
|
@ -649,6 +651,12 @@ public class DownloadActivity extends BaseDownloadActivity implements RegionDial
|
|||
|
||||
initFreeVersionBanner();
|
||||
updateFreeVersionBanner();
|
||||
downloadProgressLayout.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
new ActiveDownloadsDialogFragment().show(ctx.getSupportFragmentManager(), "dialog");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateProgress(int countedDownloads,
|
||||
|
@ -742,4 +750,84 @@ public class DownloadActivity extends BaseDownloadActivity implements RegionDial
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ActiveDownloadsDialogFragment extends DialogFragment {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new Builder(getActivity());
|
||||
builder.setTitle(R.string.downloads).setNegativeButton(R.string.shared_string_cancel, null);
|
||||
Collection<List<DownloadEntry>> vs =
|
||||
DownloadActivity.downloadListIndexThread.getEntriesToDownload().values();
|
||||
ArrayList<DownloadEntry> downloadEntries = new ArrayList<>();
|
||||
for (List<DownloadEntry> list : vs) {
|
||||
downloadEntries.addAll(list);
|
||||
}
|
||||
builder.setAdapter(new DownloadEntryAdapter(getActivity(), downloadEntries), null);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private static class DownloadEntryAdapter extends ArrayAdapter<DownloadEntry> {
|
||||
private final Drawable deleteDrawable;
|
||||
|
||||
public DownloadEntryAdapter(Context context, List<DownloadEntry> objects) {
|
||||
super(context, R.layout.two_line_with_images_list_item, objects);
|
||||
deleteDrawable = ((OsmandApplication) context.getApplicationContext()).getIconsCache()
|
||||
.getPaintedContentIcon(R.drawable.ic_action_remove_dark,
|
||||
context.getResources().getColor(R.color.dash_search_icon_dark));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.two_line_with_images_list_item, parent, false);
|
||||
DownloadEntryViewHolder viewHolder =
|
||||
new DownloadEntryViewHolder(convertView, deleteDrawable);
|
||||
convertView.setTag(viewHolder);
|
||||
}
|
||||
DownloadEntryViewHolder viewHolder = (DownloadEntryViewHolder) convertView.getTag();
|
||||
viewHolder.bindDownloadEntry(getItem(position));
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DownloadEntryViewHolder {
|
||||
private final TextView nameTextView;
|
||||
private final TextView descrTextView;
|
||||
private final ImageView leftImageView;
|
||||
private final ImageView rightImageButton;
|
||||
private final Button rightButton;
|
||||
private final ProgressBar progressBar;
|
||||
private final TextView mapDateTextView;
|
||||
private final Drawable deleteDrawable;
|
||||
|
||||
private DownloadEntryViewHolder(View convertView, Drawable deleteDrawable) {
|
||||
this.deleteDrawable = deleteDrawable;
|
||||
nameTextView = (TextView) convertView.findViewById(R.id.name);
|
||||
descrTextView = (TextView) convertView.findViewById(R.id.description);
|
||||
leftImageView = (ImageView) convertView.findViewById(R.id.leftImageView);
|
||||
rightImageButton = (ImageView) convertView.findViewById(R.id.rightImageButton);
|
||||
rightButton = (Button) convertView.findViewById(R.id.rightButton);
|
||||
progressBar = (ProgressBar) convertView.findViewById(R.id.progressBar);
|
||||
mapDateTextView = (TextView) convertView.findViewById(R.id.mapDateTextView);
|
||||
}
|
||||
public void bindDownloadEntry(DownloadEntry downloadEntry) {
|
||||
nameTextView.setText(downloadEntry.baseName);
|
||||
descrTextView.setText(String.format("%1$s MBb from %2$s Mb", 123.440,
|
||||
downloadEntry.sizeMB));
|
||||
rightImageButton.setImageDrawable(deleteDrawable);
|
||||
rightImageButton.setVisibility(View.VISIBLE);
|
||||
rightImageButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
}
|
||||
});
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
progressBar.setIndeterminate(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,4 @@ public class DownloadEntry {
|
|||
this.assetName = assetName;
|
||||
isAsset = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package net.osmand.plus.download;
|
||||
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
|
@ -30,7 +28,6 @@ import net.osmand.plus.WorldRegion;
|
|||
import net.osmand.plus.base.BasicProgressAsyncTask;
|
||||
import net.osmand.plus.download.DownloadFileHelper.DownloadFileShowWarning;
|
||||
import net.osmand.plus.download.DownloadOsmandIndexesHelper.AssetIndexItem;
|
||||
import net.osmand.plus.download.items.ItemsListBuilder;
|
||||
import net.osmand.plus.helpers.DatabaseHelper;
|
||||
import net.osmand.plus.resources.ResourceManager;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
@ -304,7 +301,10 @@ public class DownloadIndexesThread {
|
|||
} else if (o instanceof String) {
|
||||
String message = (String) o;
|
||||
if (!message.equals("I/O error occurred : Interrupted")) {
|
||||
AccessibleToast.makeText(ctx, message, Toast.LENGTH_LONG).show();
|
||||
if (uiActivity == null ||
|
||||
!message.equals(uiActivity.getString(R.string.shared_string_download_successful))) {
|
||||
AccessibleToast.makeText(ctx, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -472,7 +472,6 @@ public class DownloadIndexesThread {
|
|||
@Override
|
||||
public void showWarning(String warning) {
|
||||
publishProgress(warning);
|
||||
|
||||
}
|
||||
|
||||
public boolean downloadFile(DownloadEntry de, List<File> filesToReindex, boolean forceWifi)
|
||||
|
|
|
@ -70,7 +70,6 @@ public class ItemViewHolder {
|
|||
rightButton = (Button) convertView.findViewById(R.id.rightButton);
|
||||
progressBar = (ProgressBar) convertView.findViewById(R.id.progressBar);
|
||||
mapDateTextView = (TextView) convertView.findViewById(R.id.mapDateTextView);
|
||||
;
|
||||
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = convertView.getContext().getTheme();
|
||||
|
@ -108,11 +107,6 @@ public class ItemViewHolder {
|
|||
}
|
||||
if ((indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE ||
|
||||
indexItem.getType() == DownloadActivityType.HILLSHADE_FILE) && srtmDisabled) {
|
||||
if (indexItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) {
|
||||
nameTextView.setText(context.getString(R.string.srtm_plugin_disabled));
|
||||
} else {
|
||||
nameTextView.setText(context.getString(R.string.hillshade_layer_disabled));
|
||||
}
|
||||
OsmandPlugin srtmPlugin = OsmandPlugin.getPlugin(SRTMPlugin.class);
|
||||
if (srtmPlugin == null || srtmPlugin.needsInstallation()) {
|
||||
rightButtonAction = RightButtonAction.ASK_FOR_SRTM_PLUGIN_PURCHASE;
|
||||
|
@ -124,7 +118,8 @@ public class ItemViewHolder {
|
|||
} else if (indexItem.getType() == DownloadActivityType.WIKIPEDIA_FILE && freeVersion) {
|
||||
rightButtonAction = RightButtonAction.ASK_FOR_FULL_VERSION_PURCHASE;
|
||||
disabled = true;
|
||||
} else if (showTypeInTitle) {
|
||||
}
|
||||
if (showTypeInTitle) {
|
||||
nameTextView.setText(indexItem.getType().getString(context));
|
||||
} else {
|
||||
nameTextView.setText(indexItem.getVisibleName(context, context.getMyApplication().getRegions()));
|
||||
|
@ -196,9 +191,8 @@ public class ItemViewHolder {
|
|||
|
||||
if (indexFileNames != null && indexItem.isAlreadyDownloaded(indexFileNames)) {
|
||||
boolean outdated = false;
|
||||
String date = null;
|
||||
String date;
|
||||
if (indexItem.getType() == DownloadActivityType.HILLSHADE_FILE) {
|
||||
// TODO write logic for outdated
|
||||
date = indexItem.getDate(dateFormat);
|
||||
} else {
|
||||
String sfName = indexItem.getTargetFileName();
|
||||
|
@ -212,7 +206,6 @@ public class ItemViewHolder {
|
|||
int colorId = outdated ? R.color.color_distance : R.color.color_ok;
|
||||
mapDateTextView.setTextColor(context.getResources().getColor(colorId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void bindRegion(WorldRegion region, DownloadActivity context) {
|
||||
|
@ -227,6 +220,8 @@ public class ItemViewHolder {
|
|||
}
|
||||
}
|
||||
descrTextView.setVisibility(View.GONE);
|
||||
mapDateTextView.setVisibility(View.GONE);
|
||||
|
||||
leftImageView.setImageDrawable(getContextIcon(context, R.drawable.ic_map));
|
||||
rightImageButton.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
|
|
@ -65,11 +65,11 @@ public class RegionDialogFragment extends DialogFragment{
|
|||
toolbar.setTitle(region.getName());
|
||||
}
|
||||
}
|
||||
getDownloadActivity().initFreeVersionBanner(view);
|
||||
getDownloadActivity().registerFreeVersionBanner(view);
|
||||
listener = new DialogDismissListener() {
|
||||
@Override
|
||||
public void onDialogDismissed() {
|
||||
getDownloadActivity().initFreeVersionBanner(view);
|
||||
getDownloadActivity().registerFreeVersionBanner(view);
|
||||
}
|
||||
};
|
||||
return view;
|
||||
|
|
|
@ -101,7 +101,7 @@ public class SearchDialogFragment extends DialogFragment {
|
|||
SearchItemsFragment.createInstance(searchText), SearchItemsFragment.TAG).commit();
|
||||
}
|
||||
|
||||
getDownloadActivity().initFreeVersionBanner(view);
|
||||
getDownloadActivity().registerFreeVersionBanner(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ public class VoiceDialogFragment extends DialogFragment {
|
|||
ItemsListBuilder builder = getDownloadActivity().getItemsBuilder();
|
||||
toolbar.setTitle(builder.getVoicePromtName(voicePromptsType));
|
||||
}
|
||||
((DownloadActivity)getActivity()).initFreeVersionBanner(view);
|
||||
((DownloadActivity)getActivity()).registerFreeVersionBanner(view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ import net.osmand.plus.Version;
|
|||
import net.osmand.plus.WorldRegion;
|
||||
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
|
||||
import net.osmand.plus.activities.OsmandExpandableListFragment;
|
||||
import net.osmand.plus.download.BaseDownloadActivity;
|
||||
import net.osmand.plus.download.DownloadActivity;
|
||||
import net.osmand.plus.download.IndexItem;
|
||||
import net.osmand.plus.download.items.ItemsListBuilder.VoicePromptsType;
|
||||
import net.osmand.plus.openseamapsplugin.NauticalMapsPlugin;
|
||||
import net.osmand.plus.srtmplugin.SRTMPlugin;
|
||||
|
@ -141,6 +143,15 @@ public class WorldItemsFragment extends OsmandExpandableListFragment {
|
|||
getDownloadActivity().showDialog(getActivity(),
|
||||
VoiceDialogFragment.createInstance(VoicePromptsType.TTS));
|
||||
}
|
||||
}else if (groupPosition == worldMapsIndex) {
|
||||
if(((ItemViewHolder) v.getTag()).isItemAvailable()) {
|
||||
IndexItem indexItem = ((ItemsListBuilder.ResourceItem)
|
||||
listAdapter.getChild(groupPosition, childPosition)).getIndexItem();
|
||||
((BaseDownloadActivity) getActivity())
|
||||
.startDownload(indexItem);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue