diff options
Diffstat (limited to 'main/src/cgeo/geocaching/utils')
| -rw-r--r-- | main/src/cgeo/geocaching/utils/AngleUtils.java | 8 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/CryptUtils.java | 18 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/HtmlUtils.java | 25 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/IOUtils.java | 22 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/ImageHelper.java | 11 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/LazyInitializedList.java | 98 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java | 2 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java | 21 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/Log.java | 34 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/LogTemplateProvider.java | 22 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/MatcherWrapper.java | 91 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/PeriodicHandler.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/TranslationUtils.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/XmlUtils.java | 41 |
14 files changed, 289 insertions, 114 deletions
diff --git a/main/src/cgeo/geocaching/utils/AngleUtils.java b/main/src/cgeo/geocaching/utils/AngleUtils.java index e2b4a66..6e59a91 100644 --- a/main/src/cgeo/geocaching/utils/AngleUtils.java +++ b/main/src/cgeo/geocaching/utils/AngleUtils.java @@ -8,9 +8,11 @@ public class AngleUtils { /** * Return the angle to turn of to go from an angle to the other - * - * @param from the origin angle in degrees - * @param to the target angle in degreees + * + * @param from + * the origin angle in degrees + * @param to + * the target angle in degrees * @return a value in degrees, in the [-180, 180[ range */ public static float difference(final float from, final float to) { diff --git a/main/src/cgeo/geocaching/utils/CryptUtils.java b/main/src/cgeo/geocaching/utils/CryptUtils.java index f04327e..df2baa0 100644 --- a/main/src/cgeo/geocaching/utils/CryptUtils.java +++ b/main/src/cgeo/geocaching/utils/CryptUtils.java @@ -46,16 +46,14 @@ public final class CryptUtils { boolean plaintext = false; final int length = text.length(); - int c; - int capitalized; for (int index = 0; index < length; index++) { - c = text.charAt(index); + int c = text.charAt(index); if (c == '[') { plaintext = true; } else if (c == ']') { plaintext = false; } else if (!plaintext) { - capitalized = c & 32; + int capitalized = c & 32; c &= ~capitalized; c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c) | capitalized; @@ -73,7 +71,7 @@ public final class CryptUtils { digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { - Log.e("cgBase.md5: " + e.toString()); + Log.e("cgBase.md5", e); } return hashed; @@ -87,7 +85,7 @@ public final class CryptUtils { digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { - Log.e("cgBase.sha1: " + e.toString()); + Log.e("cgBase.sha1", e); } return hashed; @@ -102,7 +100,7 @@ public final class CryptUtils { mac.init(secretKeySpec); macBytes = mac.doFinal(text.getBytes()); } catch (Exception e) { - Log.e("cgBase.hashHmac: " + e.toString()); + Log.e("cgBase.hashHmac", e); } return macBytes; @@ -116,16 +114,14 @@ public final class CryptUtils { boolean plaintext = false; final int length = span.length(); - int c; - int capitalized; for (int index = 0; index < length; index++) { - c = span.charAt(index); + int c = span.charAt(index); if (c == '[') { plaintext = true; } else if (c == ']') { plaintext = false; } else if (!plaintext) { - capitalized = c & 32; + int capitalized = c & 32; c &= ~capitalized; c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c) | capitalized; diff --git a/main/src/cgeo/geocaching/utils/HtmlUtils.java b/main/src/cgeo/geocaching/utils/HtmlUtils.java index a54ba57..30aa19b 100644 --- a/main/src/cgeo/geocaching/utils/HtmlUtils.java +++ b/main/src/cgeo/geocaching/utils/HtmlUtils.java @@ -53,4 +53,29 @@ public class HtmlUtils { return StringUtils.replace(result, "<br />", "\n").trim(); } + /** + * Convert any non-Latin characters into HTML unicode entities + * + * @param input + * String + * @return output String + */ + public static String convertNonLatinCharactersToHTML(final String input) { + final int inputLen = input.length(); + final StringBuilder output = new StringBuilder(); + + for (int i = 0; i < inputLen; i++) { + char c = input.charAt(i); + + if (c > 300) { + output.append("&#"); + output.append(Integer.toString(c)); + output.append(';'); + } else { + output.append(c); + } + } + + return output.toString(); + } } diff --git a/main/src/cgeo/geocaching/utils/IOUtils.java b/main/src/cgeo/geocaching/utils/IOUtils.java new file mode 100644 index 0000000..df90da3 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/IOUtils.java @@ -0,0 +1,22 @@ +package cgeo.geocaching.utils; + +import java.io.Closeable; +import java.io.IOException; + +final public class IOUtils { + + private IOUtils() { + // utility class + } + + public static void closeQuietly(final Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (final IOException e) { + Log.w("closeQuietly: unable to close " + closeable, e); + } + } + } + +} diff --git a/main/src/cgeo/geocaching/utils/ImageHelper.java b/main/src/cgeo/geocaching/utils/ImageHelper.java index 4c18b06..98cad64 100644 --- a/main/src/cgeo/geocaching/utils/ImageHelper.java +++ b/main/src/cgeo/geocaching/utils/ImageHelper.java @@ -1,13 +1,12 @@ package cgeo.geocaching.utils; import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.compatibility.Compatibility; -import android.content.Context; import android.graphics.Bitmap; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; -import android.view.Display; -import android.view.WindowManager; public class ImageHelper { @@ -24,9 +23,9 @@ public class ImageHelper { */ public static BitmapDrawable scaleBitmapToFitDisplay(final Bitmap image) { final cgeoapplication app = cgeoapplication.getInstance(); - final Display display = ((WindowManager) app.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); - final int maxWidth = display.getWidth() - 25; - final int maxHeight = display.getHeight() - 25; + Point displaySize = Compatibility.getDisplaySize(); + final int maxWidth = displaySize.x - 25; + final int maxHeight = displaySize.y - 25; Bitmap result = image; int width = image.getWidth(); diff --git a/main/src/cgeo/geocaching/utils/LazyInitializedList.java b/main/src/cgeo/geocaching/utils/LazyInitializedList.java index 25af811..27649e8 100644 --- a/main/src/cgeo/geocaching/utils/LazyInitializedList.java +++ b/main/src/cgeo/geocaching/utils/LazyInitializedList.java @@ -1,103 +1,63 @@ package cgeo.geocaching.utils; +import java.util.AbstractList; import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; import java.util.List; +import java.util.concurrent.Callable; -public abstract class LazyInitializedList<ElementType> implements Iterable<ElementType> { +public abstract class LazyInitializedList<ElementType> extends AbstractList<ElementType> implements Callable<List<ElementType>> { private volatile List<ElementType> list; - private void initializeList() { + private List<ElementType> getList() { if (list == null) { - synchronized (this) { - if (list == null) { - list = loadFromDatabase(); + synchronized(this) { + try { + list = call(); + if (list == null) { + Log.e("LazyInitializedList.getList: null result"); + } + } catch (final Exception e) { + Log.e("LazyInitializedList.getList", e); } } } + return list; } - protected abstract List<ElementType> loadFromDatabase(); - - public void add(final ElementType element) { - initializeList(); - list.add(element); - } - - public void prepend(final ElementType element) { - initializeList(); - list.add(0, element); - } - - public void set(final List<ElementType> elements) { - if (elements != null) { - list = new ArrayList<ElementType>(elements); - } else { - list = new ArrayList<ElementType>(); - } - } - - public void set(LazyInitializedList<ElementType> other) { - if (other != null) { - list = new ArrayList<ElementType>(other.asList()); - } else { - list = new ArrayList<ElementType>(); - } + @Override + public boolean add(final ElementType element) { + return getList().add(element); } - public boolean isEmpty() { - initializeList(); - return list.isEmpty(); + @Override + public ElementType set(final int index, final ElementType element) { + return getList().set(index, element); } + @Override public ElementType remove(final int index) { - initializeList(); - return list.remove(index); + return getList().remove(index); } + @Override public void add(int index, final ElementType element) { - initializeList(); - list.add(index, element); + getList().add(index, element); } + @Override public int size() { - initializeList(); - return list.size(); + return getList().size(); } @Override - public Iterator<ElementType> iterator() { - initializeList(); - return list.iterator(); - } - public ElementType get(final int index) { - initializeList(); - return list.get(index); + return getList().get(index); } - public boolean contains(final ElementType element) { - initializeList(); - return list.contains(element); - } - - public boolean isNotEmpty() { - initializeList(); - return !list.isEmpty(); - } - - /** - * @return an unmodifiable list of the elements - */ - public List<ElementType> asList() { - initializeList(); - return Collections.unmodifiableList(list); + @Override + public void clear() { + list = new ArrayList<ElementType>(); } - public int indexOf(ElementType element) { - initializeList(); - return list.indexOf(element); - } } diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java index f0bc4f5..6122532 100644 --- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java +++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java @@ -16,7 +16,7 @@ import java.util.Map; */ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> { - private static enum OperationModes { + private enum OperationModes { LRU_CACHE, BOUNDED } diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java index b654fd6..698d38a 100644 --- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java +++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java @@ -9,7 +9,7 @@ import java.util.List; /** * Synchronized set wrapper for the LeastRecentlyUsedMap. - * + * * This code is heavily based on the HashSet code that represent Map as a Set. * Unfortunately HashSet does not allow to use a custom Map as its Storage. * Therefore overriding removeEldestEntry() is impossible for a normal LinkedHashSet. @@ -50,7 +50,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E> /** * Synchronized access to set size * Copy of the HashSet code if size() - * + * * @see HashSet */ @Override @@ -61,7 +61,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E> /** * Synchronized check of set emptiness * Copy of the HashSet code if isEmpty() - * + * * @see HashSet */ @Override @@ -72,7 +72,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E> /** * Synchronized check for containment * Copy of the HashSet code if contains() - * + * * @see HashSet */ @Override @@ -83,18 +83,21 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E> /** * Synchronized addition of an item * Copy of the HashSet code if add() - * + * * @see HashSet */ @Override public synchronized boolean add(E e) { + if (e == null) { + throw new IllegalArgumentException("LeastRecentlyUsedSet cannot take null element"); + } return map.put(e, PRESENT) == null; } /** * Synchronized removal of a contained item * Copy of the HashSet code if remove() - * + * * @see HashSet */ @Override @@ -117,7 +120,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E> /** * Synchronized clearing of the set * Copy of the HashSet code if clear() - * + * * @see HashSet */ @Override @@ -128,12 +131,12 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E> /** * (synchronized) Clone of the set * Copy of the HashSet code if clone() - * + * * @see HashSet */ @Override @SuppressWarnings("unchecked") - public Object clone() { + public Object clone() throws CloneNotSupportedException { try { synchronized (this) { final LeastRecentlyUsedSet<E> newSet = (LeastRecentlyUsedSet<E>) super.clone(); diff --git a/main/src/cgeo/geocaching/utils/Log.java b/main/src/cgeo/geocaching/utils/Log.java index 6213661..6d57b75 100644 --- a/main/src/cgeo/geocaching/utils/Log.java +++ b/main/src/cgeo/geocaching/utils/Log.java @@ -1,5 +1,11 @@ package cgeo.geocaching.utils; +import android.os.Environment; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; final public class Log { @@ -9,6 +15,7 @@ final public class Log { * the debug flag is cached here so that we don't need to access the settings every time we have to evaluate it */ private static boolean isDebug = true; + private static boolean first = true; public static boolean isDebug() { return isDebug; @@ -74,4 +81,31 @@ final public class Log { public static void e(final String msg, final Throwable t) { android.util.Log.e(TAG, msg, t); } + + /** + * Log the whole content of a string into "/sdcard/cgeo-debug.log". + * <br/> + * Sometimes, the string we want to work on while debugging or developing a new feature is too long to + * be fully stored in Android logcat. This method will log the content of the string in a file named + * "/sdcard/cgeo-debug.log". The file will be reset at every run, and if called several times during a run, + * the contents will be appended to one another. + * <br/> + * <strong>This method should never be called in production.</strong> + * + * @param msg the message to log, or to add to the log if other messages have been stored in the same run + */ + public synchronized static void logToFile(final String msg) { + final File file = new File(Environment.getExternalStorageDirectory(), "cgeo-debug.log"); + if (first) { + first = false; + file.delete(); + } + try { + final Writer writer = new FileWriter(file, true); + writer.write(msg); + writer.close(); + } catch (final IOException e) { + Log.e("logToFile: cannot write to " + file, e); + } + } } diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java index 7cacd9d..0a8e547 100644 --- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java +++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java @@ -2,8 +2,8 @@ package cgeo.geocaching.utils; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgTrackable; +import cgeo.geocaching.Trackable; +import cgeo.geocaching.Geocache; import cgeo.geocaching.connector.gc.GCConstants; import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.network.Network; @@ -28,15 +28,15 @@ public class LogTemplateProvider { * */ public static class LogContext { - private cgCache cache; - private cgTrackable trackable; + private Geocache cache; + private Trackable trackable; private boolean offline = false; - public LogContext(final cgCache cache) { + public LogContext(final Geocache cache) { this(cache, false); } - public LogContext(final cgTrackable trackable) { + public LogContext(final Trackable trackable) { this.trackable = trackable; } @@ -44,16 +44,16 @@ public class LogTemplateProvider { this(null, offline); } - public LogContext(final cgCache cache, boolean offline) { + public LogContext(final Geocache cache, boolean offline) { this.cache = cache; this.offline = offline; } - public cgCache getCache() { + public Geocache getCache() { return cache; } - public cgTrackable getTrackable() { + public Trackable getTrackable() { return trackable; } @@ -148,11 +148,11 @@ public class LogTemplateProvider { @Override public String getValue(final LogContext context) { - cgTrackable trackable = context.getTrackable(); + Trackable trackable = context.getTrackable(); if (trackable != null) { return trackable.getOwner(); } - cgCache cache = context.getCache(); + Geocache cache = context.getCache(); if (cache != null) { return cache.getOwnerDisplayName(); } diff --git a/main/src/cgeo/geocaching/utils/MatcherWrapper.java b/main/src/cgeo/geocaching/utils/MatcherWrapper.java new file mode 100644 index 0000000..c3c1663 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/MatcherWrapper.java @@ -0,0 +1,91 @@ +package cgeo.geocaching.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Wrapper around the regex {@link Matcher} class. This implementation optimizes the memory usage of the matched + * Strings. + * + */ +public class MatcherWrapper { + private final Matcher matcher; + + public MatcherWrapper(Pattern pattern, String input) { + this.matcher = pattern.matcher(input); + } + + /** + * see {@link Matcher#find()} + */ + public boolean find() { + return matcher.find(); + } + + /** + * see {@link Matcher#group(int)} + */ + public String group(int index) { + return newString(matcher.group(index)); + } + + /** + * This method explicitly creates a new String instance from an already existing String. This is necessary to avoid + * huge memory leaks in our parser. If we do regular expression matching on large Strings, the returned matches are + * otherwise memory mapped substrings of the huge original String, therefore blocking the garbage collector from + * removing the huge input String. + * <p> + * Do not change this method, even if Findbugs and other tools will report a violation for that line! + * + * @param input + * @return + */ + private static String newString(String input) { + if (input == null) { + return null; + } + return new String(input); // DON'T REMOVE THE "new String" HERE! + } + + /** + * see {@link Matcher#groupCount()} + */ + public int groupCount() { + return matcher.groupCount(); + } + + /** + * see {@link Matcher#group()} + */ + public String group() { + return newString(matcher.group()); + } + + /** + * see {@link Matcher#start()} + */ + public int start() { + return matcher.start(); + } + + /** + * see {@link Matcher#replaceAll(String)} + */ + public String replaceAll(String replacement) { + return newString(matcher.replaceAll(replacement)); + } + + /** + * see {@link Matcher#matches()} + */ + public boolean matches() { + return matcher.matches(); + } + + /** + * see {@link Matcher#replaceFirst(String)} + */ + public String replaceFirst(String replacement) { + return newString(matcher.replaceFirst(replacement)); + } +} diff --git a/main/src/cgeo/geocaching/utils/PeriodicHandler.java b/main/src/cgeo/geocaching/utils/PeriodicHandler.java index 3f6c345..2759580 100644 --- a/main/src/cgeo/geocaching/utils/PeriodicHandler.java +++ b/main/src/cgeo/geocaching/utils/PeriodicHandler.java @@ -26,7 +26,7 @@ abstract public class PeriodicHandler extends Handler { * @param period * The period in milliseconds. */ - public PeriodicHandler(final long period) { + protected PeriodicHandler(final long period) { this.period = period; } @@ -48,6 +48,9 @@ abstract public class PeriodicHandler extends Handler { case ACT: sendEmptyMessageDelayed(ACT, period); act(); + break; + default: + throw new UnsupportedOperationException(); } } diff --git a/main/src/cgeo/geocaching/utils/TranslationUtils.java b/main/src/cgeo/geocaching/utils/TranslationUtils.java index a29c5a7..4d318f0 100644 --- a/main/src/cgeo/geocaching/utils/TranslationUtils.java +++ b/main/src/cgeo/geocaching/utils/TranslationUtils.java @@ -1,12 +1,11 @@ package cgeo.geocaching.utils; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.network.Network; import android.content.Intent; import android.net.Uri; -import java.net.URLEncoder; - /** * Utilities used for translating */ @@ -30,7 +29,7 @@ public final class TranslationUtils { * @return URI ready to be parsed */ private static String buildTranslationURI(final String toLang, final String text) { - String content = URLEncoder.encode(text); + String content = Network.encode(text); // the app works better without the "+", the website works better with "+", therefore assume using the app if installed if (ProcessUtils.isInstalled(TRANSLATION_APP)) { content = content.replace("+", "%20"); diff --git a/main/src/cgeo/geocaching/utils/XmlUtils.java b/main/src/cgeo/geocaching/utils/XmlUtils.java new file mode 100644 index 0000000..4e08f42 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/XmlUtils.java @@ -0,0 +1,41 @@ +package cgeo.geocaching.utils; + +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; + +public class XmlUtils { + + private XmlUtils() { + // Do not instantiate + } + + /** + * Insert an attribute-less tag with enclosed text in a XML serializer output. + * + * @param serializer an XML serializer + * @param prefix an XML prefix, see {@link XmlSerializer#startTag(String, String)} + * @param tag an XML tag + * @param text some text to insert + * @throws IOException + */ + public static void simpleText(final XmlSerializer serializer, final String prefix, final String tag, final String text) throws IOException { + serializer.startTag(prefix, tag); + serializer.text(text); + serializer.endTag(prefix, tag); + } + + /** + * Insert pairs of attribute-less tags and enclosed texts in a XML serializer output + * + * @param serializer an XML serializer + * @param prefix an XML prefix, see {@link XmlSerializer#startTag(String, String)} shared by all tags + * @param tagAndText an XML tag, the corresponding text, another XML tag, the corresponding text, … + * @throws IOException + */ + public static void multipleTexts(final XmlSerializer serializer, final String prefix, final String... tagAndText) throws IOException { + for (int i = 0; i < tagAndText.length; i += 2) { + simpleText(serializer, prefix, tagAndText[i], tagAndText[i+1]); + } + } +} |
