diff options
Diffstat (limited to 'main/src/cgeo/geocaching/files')
| -rw-r--r-- | main/src/cgeo/geocaching/files/AbstractFileListActivity.java | 12 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/FileParser.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/GPXImporter.java | 4 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/GPXParser.java | 27 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/LocParser.java | 4 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/LocalStorage.java | 42 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/ProgressInputStream.java | 18 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/SimpleDirChooser.java | 30 |
8 files changed, 93 insertions, 49 deletions
diff --git a/main/src/cgeo/geocaching/files/AbstractFileListActivity.java b/main/src/cgeo/geocaching/files/AbstractFileListActivity.java index b0aba58..35e6265 100644 --- a/main/src/cgeo/geocaching/files/AbstractFileListActivity.java +++ b/main/src/cgeo/geocaching/files/AbstractFileListActivity.java @@ -2,12 +2,12 @@ package cgeo.geocaching.files; import cgeo.geocaching.Intents; import cgeo.geocaching.R; -import cgeo.geocaching.StoredList; import cgeo.geocaching.activity.AbstractListActivity; +import cgeo.geocaching.list.StoredList; import cgeo.geocaching.utils.FileUtils; import cgeo.geocaching.utils.Log; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; @@ -66,7 +66,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext if (waitDialog != null) { waitDialog.dismiss(); } - if (CollectionUtils.isEmpty(files)) { + if (CollectionUtils.isEmpty(files) && requireFiles()) { showToast(res.getString(R.string.file_list_no_files)); finish(); } else if (adapter != null) { @@ -104,7 +104,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext if (searchingThread != null && searchingThread.isAlive()) { searchingThread.notifyEnd(); } - if (files.isEmpty()) { + if (files.isEmpty() && requireFiles()) { finish(); } } @@ -121,6 +121,10 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext } + protected boolean requireFiles() { + return true; + } + protected abstract T getAdapter(List<File> files); private void setAdapter() { diff --git a/main/src/cgeo/geocaching/files/FileParser.java b/main/src/cgeo/geocaching/files/FileParser.java index f979d74..396a589 100644 --- a/main/src/cgeo/geocaching/files/FileParser.java +++ b/main/src/cgeo/geocaching/files/FileParser.java @@ -2,7 +2,8 @@ package cgeo.geocaching.files; import cgeo.geocaching.Geocache; import cgeo.geocaching.utils.CancellableHandler; -import cgeo.geocaching.utils.IOUtils; + +import org.apache.commons.io.IOUtils; import java.io.BufferedInputStream; import java.io.BufferedReader; @@ -51,7 +52,7 @@ public abstract class FileParser { protected static StringBuilder readStream(InputStream is, CancellableHandler progressHandler) throws IOException { final StringBuilder buffer = new StringBuilder(); ProgressInputStream progressInputStream = new ProgressInputStream(is); - final BufferedReader input = new BufferedReader(new InputStreamReader(progressInputStream)); + final BufferedReader input = new BufferedReader(new InputStreamReader(progressInputStream, "UTF-8")); try { String line; diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index 3f11c26..bf0aa72 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -4,7 +4,7 @@ import cgeo.geocaching.Geocache; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.StaticMapsProvider; -import cgeo.geocaching.cgData; +import cgeo.geocaching.DataStore; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.enumerations.LoadFlags; @@ -175,7 +175,7 @@ public class GPXImporter { private boolean importStaticMaps(final SearchResult importedCaches) { int storedCacheMaps = 0; for (final String geocode : importedCaches.getGeocodes()) { - final Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); + final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); if (cache != null) { Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode); StaticMapsProvider.downloadMaps(cache); diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java index 3358759..e01c191 100644 --- a/main/src/cgeo/geocaching/files/GPXParser.java +++ b/main/src/cgeo/geocaching/files/GPXParser.java @@ -1,13 +1,12 @@ package cgeo.geocaching.files; +import cgeo.geocaching.CgeoApplication; +import cgeo.geocaching.DataStore; import cgeo.geocaching.Geocache; import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; -import cgeo.geocaching.StoredList; import cgeo.geocaching.Trackable; import cgeo.geocaching.Waypoint; -import cgeo.geocaching.cgData; -import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; @@ -17,9 +16,11 @@ import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.list.StoredList; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.MatcherWrapper; +import cgeo.geocaching.utils.SynchronizedDateFormat; import org.apache.commons.lang3.StringUtils; import org.xml.sax.Attributes; @@ -35,7 +36,6 @@ import android.util.Xml; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -47,9 +47,9 @@ import java.util.regex.Pattern; public abstract class GPXParser extends FileParser { - private static final SimpleDateFormat formatSimple = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US); // 2010-04-20T07:00:00 - private static final SimpleDateFormat formatSimpleZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); // 2010-04-20T07:00:00Z - private static final SimpleDateFormat formatTimezone = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); // 2010-04-20T01:01:03-04:00 + private static final SynchronizedDateFormat formatSimple = new SynchronizedDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US); // 2010-04-20T07:00:00 + private static final SynchronizedDateFormat formatSimpleZ = new SynchronizedDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); // 2010-04-20T07:00:00Z + private static final SynchronizedDateFormat formatTimezone = new SynchronizedDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); // 2010-04-20T01:01:03-04:00 /** * Attention: case sensitive geocode pattern to avoid matching normal words in the name or description of the cache. @@ -205,7 +205,7 @@ public abstract class GPXParser extends FileParser { // get text for string String stringName; try { - stringName = cgeoapplication.getInstance().getResources().getResourceName(stringId); + stringName = CgeoApplication.getInstance().getResources().getResourceName(stringId); } catch (final NullPointerException e) { return null; } @@ -312,10 +312,10 @@ public abstract class GPXParser extends FileParser { // finally store the cache in the database result.add(geocode); - cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + DataStore.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); // avoid the cachecache using lots of memory for caches which the user did not actually look at - cgData.removeAllFromCache(); + DataStore.removeAllFromCache(); showProgressMessage(progressHandler, progressStream.getProgress()); } else if (StringUtils.isNotBlank(cache.getName()) && StringUtils.containsIgnoreCase(type, "waypoint")) { @@ -331,7 +331,7 @@ public abstract class GPXParser extends FileParser { if (cache.getName().length() > 2) { final String cacheGeocodeForWaypoint = "GC" + cache.getName().substring(2).toUpperCase(Locale.US); // lookup cache for waypoint in already parsed caches - final Geocache cacheForWaypoint = cgData.loadCache(cacheGeocodeForWaypoint, LoadFlags.LOAD_CACHE_OR_DB); + final Geocache cacheForWaypoint = DataStore.loadCache(cacheGeocodeForWaypoint, LoadFlags.LOAD_CACHE_OR_DB); if (cacheForWaypoint != null) { final Waypoint waypoint = new Waypoint(cache.getShortDescription(), convertWaypointSym2Type(sym), false); waypoint.setId(-1); @@ -349,7 +349,7 @@ public abstract class GPXParser extends FileParser { newPoints.add(waypoint); Waypoint.mergeWayPoints(newPoints, mergedWayPoints, true); cacheForWaypoint.setWaypoints(newPoints, false); - cgData.saveCache(cacheForWaypoint, EnumSet.of(SaveFlag.SAVE_DB)); + DataStore.saveCache(cacheForWaypoint, EnumSet.of(SaveFlag.SAVE_DB)); showProgressMessage(progressHandler, progressStream.getProgress()); } } @@ -785,9 +785,8 @@ public abstract class GPXParser extends FileParser { try { progressStream = new ProgressInputStream(stream); Xml.parse(progressStream, Xml.Encoding.UTF_8, root.getContentHandler()); - return cgData.loadCaches(result, EnumSet.of(LoadFlag.LOAD_DB_MINIMAL)); + return DataStore.loadCaches(result, EnumSet.of(LoadFlag.LOAD_DB_MINIMAL)); } catch (final SAXException e) { - Log.w("Cannot parse .gpx file as GPX " + version + ": could not parse XML - ", e); throw new ParserException("Cannot parse .gpx file as GPX " + version + ": could not parse XML", e); } } diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java index 1cfb2a3..3d01c1b 100644 --- a/main/src/cgeo/geocaching/files/LocParser.java +++ b/main/src/cgeo/geocaching/files/LocParser.java @@ -1,8 +1,8 @@ package cgeo.geocaching.files; +import cgeo.geocaching.DataStore; import cgeo.geocaching.Geocache; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.cgData; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; @@ -59,7 +59,7 @@ public final class LocParser extends FileParser { contained.add(geocode); } } - Set<Geocache> caches = cgData.loadCaches(contained, LoadFlags.LOAD_CACHE_OR_DB); + Set<Geocache> caches = DataStore.loadCaches(contained, LoadFlags.LOAD_CACHE_OR_DB); for (Geocache cache : caches) { Geocache coord = cidCoords.get(cache.getGeocode()); copyCoordToCache(coord, cache); diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java index fc82409..edbecf6 100644 --- a/main/src/cgeo/geocaching/files/LocalStorage.java +++ b/main/src/cgeo/geocaching/files/LocalStorage.java @@ -1,15 +1,16 @@ package cgeo.geocaching.files; -import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.utils.CryptUtils; import cgeo.geocaching.utils.FileUtils; -import cgeo.geocaching.utils.IOUtils; import cgeo.geocaching.utils.Log; import ch.boye.httpclientandroidlib.Header; import ch.boye.httpclientandroidlib.HttpResponse; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.Nullable; import android.os.Environment; @@ -21,11 +22,13 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.Reader; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; @@ -35,6 +38,7 @@ import java.util.List; */ public final class LocalStorage { + private static final String FILE_SYSTEM_TABLE_PATH = "/system/etc/vold.fstab"; public static final String HEADER_LAST_MODIFIED = "last-modified"; public static final String HEADER_ETAG = "etag"; @@ -86,7 +90,7 @@ public final class LocalStorage { private static File getInternalStorageBase() { if (internalStorageBase == null) { // A race condition will do no harm as the operation is idempotent. No need to synchronize. - internalStorageBase = cgeoapplication.getInstance().getApplicationContext().getFilesDir().getParentFile(); + internalStorageBase = CgeoApplication.getInstance().getApplicationContext().getFilesDir().getParentFile(); } return internalStorageBase; } @@ -99,7 +103,14 @@ public final class LocalStorage { * @return the file extension, including the leading dot, or the empty string if none could be determined */ static String getExtension(final String url) { - final String urlExt = StringUtils.substringAfterLast(url, "."); + String urlExt; + if (url.startsWith("data:")) { + // "data:image/png;base64,i53…" -> ".png" + urlExt = StringUtils.substringAfter(StringUtils.substringBefore(url, ";"), "/"); + } else { + // "http://example.com/foo/bar.png" -> ".png" + urlExt = StringUtils.substringAfterLast(url, "."); + } return urlExt.length() >= 1 && urlExt.length() <= 4 ? "." + urlExt : ""; } @@ -198,13 +209,19 @@ public final class LocalStorage { return false; } - private static void saveHeader(final String name, final HttpResponse response, final File baseFile) { + private static void saveHeader(final String name, @Nullable final HttpResponse response, final File baseFile) { final Header header = response != null ? response.getFirstHeader(name) : null; final File file = filenameForHeader(baseFile, name); if (header == null) { FileUtils.deleteIgnoringFailure(file); } else { - saveToFile(new ByteArrayInputStream(header.getValue().getBytes()), file); + try { + saveToFile(new ByteArrayInputStream(header.getValue().getBytes("UTF-8")), file); + } catch (final UnsupportedEncodingException e) { + // Do not try to display the header in the log message, as our default encoding is + // likely to be UTF-8 and it will fail as well. + Log.e("LocalStorage.saveHeader: unable to decode header", e); + } } } @@ -219,12 +236,13 @@ public final class LocalStorage { * the name of the cached resource * @param name * the name of the header ("etag" or "last-modified") - * @return null if no value has been cached, the value otherwise + * @return the cached value, or <tt>null</tt> if none has been cached */ + @Nullable public static String getSavedHeader(final File baseFile, final String name) { try { final File file = filenameForHeader(baseFile, name); - final FileReader f = new FileReader(file); + final Reader f = new InputStreamReader(new FileInputStream(file), "UTF-8"); try { // No header will be more than 256 bytes final char[] value = new char[256]; @@ -408,12 +426,12 @@ public final class LocalStorage { String extStorage = Environment.getExternalStorageDirectory().getAbsolutePath(); List<File> storages = new ArrayList<File>(); storages.add(new File(extStorage)); - File file = new File("/system/etc/vold.fstab"); + File file = new File(FILE_SYSTEM_TABLE_PATH); if (file.canRead()) { - FileReader fr = null; + Reader fr = null; BufferedReader br = null; try { - fr = new FileReader(file); + fr = new InputStreamReader(new FileInputStream(file), "UTF-8"); br = new BufferedReader(fr); String s = br.readLine(); while (s != null) { diff --git a/main/src/cgeo/geocaching/files/ProgressInputStream.java b/main/src/cgeo/geocaching/files/ProgressInputStream.java index 593949b..552aee0 100644 --- a/main/src/cgeo/geocaching/files/ProgressInputStream.java +++ b/main/src/cgeo/geocaching/files/ProgressInputStream.java @@ -4,6 +4,14 @@ import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; +/** + * Stream to measure progress of reading automatically. + * <p> + * The method @link ProgressInputStream#read(byte[]) does not need to be overridden as it delegates to @link + * ProgressInputStream#read(byte[], int, int) anyway. + * </p> + * + */ public class ProgressInputStream extends FilterInputStream { private int progress = 0; @@ -15,17 +23,13 @@ public class ProgressInputStream extends FilterInputStream { @Override public int read() throws IOException { final int read = super.read(); - progress += read; + if (read >= 0) { + progress++; + } return read; } @Override - public int read(byte[] buffer) throws IOException { - return super.read(buffer); - // don't increment here, this calls another read implementation which we already measure - } - - @Override public int read(byte[] buffer, int offset, int count) throws IOException { final int read = super.read(buffer, offset, count); progress += read; diff --git a/main/src/cgeo/geocaching/files/SimpleDirChooser.java b/main/src/cgeo/geocaching/files/SimpleDirChooser.java index 8f69b88..e59287d 100644 --- a/main/src/cgeo/geocaching/files/SimpleDirChooser.java +++ b/main/src/cgeo/geocaching/files/SimpleDirChooser.java @@ -32,17 +32,20 @@ import java.util.List; * Dialog for choosing a file or directory. */ public class SimpleDirChooser extends AbstractListActivity { + public static final String EXTRA_CHOOSE_FOR_WRITING = "chooseForWriting"; private static final String PARENT_DIR = ".. "; private File currentDir; private FileArrayAdapter adapter; private Button okButton = null; private int lastPosition = -1; + private boolean chooseForWriting = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Bundle extras = getIntent().getExtras(); currentDir = dirContaining(extras.getString(Intents.EXTRA_START_DIR)); + chooseForWriting = extras.getBoolean(SimpleDirChooser.EXTRA_CHOOSE_FOR_WRITING, false); ActivityMixin.setTheme(this); setContentView(R.layout.simple_dir_chooser); @@ -85,19 +88,20 @@ public class SimpleDirChooser extends AbstractListActivity { } private void fill(File dir) { + lastPosition = -1; EditText path = (EditText) findViewById(R.id.simple_dir_chooser_path); path.setText(this.getResources().getString(R.string.simple_dir_chooser_current_path) + " " + dir.getAbsolutePath()); final File[] dirs = dir.listFiles(new DirOnlyFilenameFilter()); List<Option> listDirs = new ArrayList<Option>(); try { for (File currentDir : dirs) { - listDirs.add(new Option(currentDir.getName(), currentDir.getAbsolutePath())); + listDirs.add(new Option(currentDir.getName(), currentDir.getAbsolutePath(), currentDir.canWrite())); } } catch (RuntimeException e) { } Collections.sort(listDirs); if (dir.getParent() != null) { - listDirs.add(0, new Option(PARENT_DIR, dir.getParent())); + listDirs.add(0, new Option(PARENT_DIR, dir.getParent(), false)); } this.adapter = new FileArrayAdapter(this, R.layout.simple_dir_item, listDirs); this.setListAdapter(adapter); @@ -138,8 +142,13 @@ public class SimpleDirChooser extends AbstractListActivity { } CheckBox check = (CheckBox) v.findViewById(R.id.CheckBox); if (check != null) { - check.setOnClickListener(new OnCheckBoxClickListener(position)); - check.setChecked(option.isChecked()); + if (!chooseForWriting || option.isWriteable()) { + check.setOnClickListener(new OnCheckBoxClickListener(position)); + check.setChecked(option.isChecked()); + check.setEnabled(true); + } else { + check.setEnabled(false); + } } } return v; @@ -196,14 +205,19 @@ public class SimpleDirChooser extends AbstractListActivity { } } + /** + * Note: this class has a natural ordering that is inconsistent with equals. + */ public static class Option implements Comparable<Option> { private final String name; private final String path; private boolean checked = false; + private boolean writeable = false; - public Option(String name, String path) { + public Option(String name, String path, boolean writeable) { this.name = name; this.path = path; + this.writeable = writeable; } public String getName() { @@ -222,6 +236,10 @@ public class SimpleDirChooser extends AbstractListActivity { this.checked = checked; } + public boolean isWriteable() { + return writeable; + } + @Override public int compareTo(Option other) { if (other != null && this.name != null) { @@ -236,7 +254,7 @@ public class SimpleDirChooser extends AbstractListActivity { @Override public boolean accept(File dir, String filename) { File file = new File(dir, filename); - return file.isDirectory() && file.canWrite(); + return file.isDirectory() && file.canRead(); } } |
