diff options
| author | Samuel Tardieu <sam@rfc1149.net> | 2011-10-06 23:33:21 +0200 |
|---|---|---|
| committer | Samuel Tardieu <sam@rfc1149.net> | 2011-10-06 23:33:21 +0200 |
| commit | cf8a6acc34f211fe1fb790a57befa86a835585dd (patch) | |
| tree | 8ebcfc8c38cf67cd745db24de98e41b8ef2d1b4a /main/src | |
| parent | f8d30878a368895ce030099287c85836a446a66e (diff) | |
| download | cgeo-cf8a6acc34f211fe1fb790a57befa86a835585dd.zip cgeo-cf8a6acc34f211fe1fb790a57befa86a835585dd.tar.gz cgeo-cf8a6acc34f211fe1fb790a57befa86a835585dd.tar.bz2 | |
Reorganize and cleanup the local storage handling
After the HTTP requests cleanup, it was time to rewrite
the local storage handling.
Code that manipulate files has been placed into a new
LocalStorage class. It can locate files on the disk,
retrieve web responses and store them, and copy files.
Diffstat (limited to 'main/src')
| -rw-r--r-- | main/src/cgeo/geocaching/Settings.java | 20 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/StaticMapsProvider.java | 98 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgCacheListAdapter.java | 2 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgData.java | 138 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgDirectionImg.java | 86 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgHtmlImg.java | 156 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgeoimages.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgeosmaps.java | 4 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/LocalStorage.java | 217 |
9 files changed, 314 insertions, 412 deletions
diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java index c45df2b..94a31f4 100644 --- a/main/src/cgeo/geocaching/Settings.java +++ b/main/src/cgeo/geocaching/Settings.java @@ -14,7 +14,6 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.res.Configuration; import android.content.res.Resources; -import android.os.Environment; import java.util.HashMap; import java.util.Locale; @@ -153,25 +152,6 @@ public final class Settings { resources.updateConfiguration(config, resources.getDisplayMetrics()); } - public static String getStorage() { - return getStorageSpecific()[0]; - } - - public static String getStorageSec() { - return getStorageSpecific()[1]; - } - - public static String[] getStorageSpecific() { - final String external = Environment.getExternalStorageDirectory() + "/" + cache + "/"; - final String data = Environment.getDataDirectory() + "/data/cgeo.geocaching/" + cache + "/"; - - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - return new String[] { external, data }; - } else { - return new String[] { data, external }; - } - } - public static boolean isLogin() { final String preUsername = sharedPrefs.getString(KEY_USERNAME, null); final String prePassword = sharedPrefs.getString(KEY_PASSWORD, null); diff --git a/main/src/cgeo/geocaching/StaticMapsProvider.java b/main/src/cgeo/geocaching/StaticMapsProvider.java index 0c21912..59990b7 100644 --- a/main/src/cgeo/geocaching/StaticMapsProvider.java +++ b/main/src/cgeo/geocaching/StaticMapsProvider.java @@ -1,25 +1,17 @@ package cgeo.geocaching; +import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.utils.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.entity.BufferedHttpEntity; -import org.apache.http.impl.client.DefaultHttpClient; import android.app.Activity; import android.content.Context; -import android.util.Log; import android.view.Display; import android.view.WindowManager; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; import java.util.Locale; public class StaticMapsProvider { @@ -29,9 +21,11 @@ public class StaticMapsProvider { */ private static final int MIN_MAP_IMAGE_BYTES = 6000; - private static void downloadMapsInThread(final cgCache cache, String latlonMap, int edge, String waypoints) { - createStorageDirectory(cache); + public static File getMapFile(final String geocode, final int level) { + return LocalStorage.getStorageFile(geocode, "map_" + level, false); + } + private static void downloadMapsInThread(final cgCache cache, String latlonMap, int edge, String waypoints) { downloadMap(cache, 20, "satellite", 1, latlonMap, edge, waypoints); downloadMap(cache, 18, "satellite", 2, latlonMap, edge, waypoints); downloadMap(cache, 16, "roadmap", 3, latlonMap, edge, waypoints); @@ -39,82 +33,22 @@ public class StaticMapsProvider { downloadMap(cache, 11, "roadmap", 5, latlonMap, edge, waypoints); } - private static void createStorageDirectory(final cgCache cache) { - File dir = new File(Settings.getStorage()); - if (dir.exists() == false) { - dir.mkdirs(); - } - dir = new File(getStaticMapsDirectory(cache)); - if (dir.exists() == false) { - dir.mkdirs(); - } - } - - private static String getStaticMapsDirectory(final cgCache cache) { - return Settings.getStorage() + cache.geocode; - } - private static void downloadMap(cgCache cache, int zoom, String mapType, int level, String latlonMap, int edge, String waypoints) { - String mapUrl = "http://maps.google.com/maps/api/staticmap?center=" + latlonMap; - String markerUrl = getMarkerUrl(cache); + final String mapUrl = "http://maps.google.com/maps/api/staticmap?center=" + latlonMap; + final String markerUrl = getMarkerUrl(cache); - String url = mapUrl + "&zoom=" + zoom + "&size=" + edge + "x" + edge + "&maptype=" + mapType + "&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints + "&sensor=false"; + final String url = mapUrl + "&zoom=" + zoom + "&size=" + edge + "x" + edge + "&maptype=" + mapType + "&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints + "&sensor=false"; - final String fileName = getStaticMapsDirectory(cache) + "/map_" + level; - HttpClient client = null; - HttpGet getMethod = null; - HttpResponse httpResponse = null; - HttpEntity entity = null; - - boolean ok = false; - - for (int i = 0; i < 3; i++) { - if (i > 0) - Log.w(Settings.tag, "cgMapImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1)); - - try { - client = new DefaultHttpClient(); - getMethod = new HttpGet(url); - httpResponse = client.execute(getMethod); - entity = httpResponse.getEntity(); - - // if image is to small, don't download and save, there is no map data for this zoom level - long contentSize = entity.getContentLength(); - if (contentSize > 0 && contentSize <= MIN_MAP_IMAGE_BYTES) { - break; - } - - final BufferedHttpEntity bufferedEntity = new BufferedHttpEntity(entity); - InputStream is = (InputStream) bufferedEntity.getContent(); - FileOutputStream fos = new FileOutputStream(fileName); - - int fileSize = 0; - try { - byte[] buffer = new byte[4096]; - int bytesRead; - while ((bytesRead = is.read(buffer)) != -1) { - fos.write(buffer, 0, bytesRead); - fileSize += bytesRead; - } - fos.flush(); - ok = true; - } catch (IOException e) { - Log.e(Settings.tag, "cgMapImg.getDrawable (saving to cache): " + e.toString()); - } finally { - is.close(); - fos.close(); - } - - // delete image if it has no contents - if (ok && fileSize < MIN_MAP_IMAGE_BYTES) { - (new File(fileName)).delete(); - } + final File file = getMapFile(cache.geocode, level); + final HttpResponse httpResponse = cgBase.request(url, null, false); - if (ok) { - break; + if (httpResponse != null) { + if (LocalStorage.saveEntityToFile(httpResponse.getEntity(), file)) { + // Delete image if it has no contents + final long fileSize = file.length(); + if (fileSize < MIN_MAP_IMAGE_BYTES) { + file.delete(); } - } catch (Exception e) { - Log.e(Settings.tag, "cgMapImg.getDrawable (downloading from web): " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/cgCacheListAdapter.java b/main/src/cgeo/geocaching/cgCacheListAdapter.java index 237b3c1..9d27491 100644 --- a/main/src/cgeo/geocaching/cgCacheListAdapter.java +++ b/main/src/cgeo/geocaching/cgCacheListAdapter.java @@ -522,7 +522,7 @@ public class cgCacheListAdapter extends ArrayAdapter<cgCache> { Bitmap dirImgPre = null; Bitmap dirImg = null; try { - dirImgPre = BitmapFactory.decodeFile(Settings.getStorage() + cache.geocode + "/direction.png"); + dirImgPre = BitmapFactory.decodeFile(cgDirectionImg.getDirectionFile(cache.geocode).getPath()); dirImg = dirImgPre.copy(Bitmap.Config.ARGB_8888, true); dirImgPre.recycle(); diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java index 00b4831..8e87fee 100644 --- a/main/src/cgeo/geocaching/cgData.java +++ b/main/src/cgeo/geocaching/cgData.java @@ -1,6 +1,7 @@ package cgeo.geocaching; import cgeo.geocaching.enumerations.CacheSize; +import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Geopoint.MalformedCoordinateException; import cgeo.geocaching.utils.CollectionUtils; @@ -20,12 +21,6 @@ import android.os.Environment; import android.util.Log; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -323,74 +318,32 @@ public class cgData { } } + private static File backupFile() { + return new File(LocalStorage.getStorage(), "cgeo.sqlite"); + } + public String backupDatabase() { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == false) { Log.w(Settings.tag, "Database wasn't backed up: no external memory"); - return null; } + final File target = backupFile(); closeDb(); - - boolean backupDone = false; - final String directoryImg = Settings.cache; - final String directoryTarget = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/"; - final String fileTarget = directoryTarget + "cgeo.sqlite"; - final String fileSource = path; - - File directoryTargetFile = new File(directoryTarget); - if (directoryTargetFile.exists() == false) { - directoryTargetFile.mkdir(); - } - - InputStream input = null; - OutputStream output = null; - try { - input = new FileInputStream(fileSource); - output = new FileOutputStream(fileTarget); - } catch (FileNotFoundException e) { - Log.e(Settings.tag, "Database wasn't backed up, could not open file: " + e.toString()); - } - - byte[] buffer = new byte[1024]; - int length; - if ((input != null) && (output != null)) { - try { - while ((length = input.read(buffer)) > 0) { - output.write(buffer, 0, length); - } - output.flush(); - backupDone = true; - } catch (IOException e) { - Log.e(Settings.tag, "Database wasn't backed up, could not read/write file: " + e.toString()); - } - } - - try { - if (output != null) { - output.close(); - } - if (input != null) { - input.close(); - } - } catch (IOException e) { - Log.e(Settings.tag, "Database wasn't backed up, could not close file: " + e.toString()); - } + final boolean backupDone = LocalStorage.copy(new File(path), target); + init(); if (backupDone) { - Log.i(Settings.tag, "Database was copied to " + fileTarget); + Log.i(Settings.tag, "Database was copied to " + target); + return target.getPath(); + } else { + Log.e(Settings.tag, "Database could not be copied to " + target); + return null; } - - init(); - - return backupDone ? fileTarget : null; } public static File isRestoreFile() { - final String directoryImg = Settings.cache; - final String fileSource = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/cgeo.sqlite"; - - File fileSourceFile = new File(fileSource); + final File fileSourceFile = backupFile(); if (fileSourceFile.exists()) { return fileSourceFile; } else { @@ -401,67 +354,20 @@ public class cgData { public boolean restoreDatabase() { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == false) { Log.w(Settings.tag, "Database wasn't restored: no external memory"); - return false; } + final File sourceFile = backupFile(); closeDb(); - - boolean restoreDone = false; - - final String directoryImg = Settings.cache; - final String fileSource = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/cgeo.sqlite"; - final String fileTarget = path; - - File fileSourceFile = new File(fileSource); - if (fileSourceFile.exists() == false) { - Log.w(Settings.tag, "Database backup was not found"); - - init(); - - return restoreDone; - } - - InputStream input = null; - OutputStream output = null; - try { - input = new FileInputStream(fileSource); - output = new FileOutputStream(fileTarget); - } catch (FileNotFoundException e) { - Log.e(Settings.tag, "Database wasn't restored, could not open file: " + e.toString()); - } - - byte[] buffer = new byte[1024]; - int length; - if ((input != null) && (output != null)) { - try { - while ((length = input.read(buffer)) > 0) { - output.write(buffer, 0, length); - } - output.flush(); - restoreDone = true; - } catch (IOException e) { - Log.e(Settings.tag, "Database wasn't restored, could not read/write file: " + e.toString()); - } - } - - try { - if (output != null) { - output.close(); - } - if (input != null) { - input.close(); - } - } catch (IOException e) { - Log.e(Settings.tag, "Database wasn't restored, could not close file: " + e.toString()); - } + final boolean restoreDone = LocalStorage.copy(sourceFile, new File(path)); + init(); if (restoreDone) { - Log.i(Settings.tag, "Database was restored"); + Log.i(Settings.tag, "Database succesfully restored from " + sourceFile.getPath()); + } else { + Log.e(Settings.tag, "Could not restore database from " + sourceFile.getPath()); } - init(); - return restoreDone; } @@ -980,7 +886,7 @@ public class cgData { private static void removeObsoleteCacheDirectories(final SQLiteDatabase db) { final Pattern oldFilePattern = Pattern.compile("^[GC|TB|O][A-Z0-9]{4,7}$"); final SQLiteStatement select = db.compileStatement("select count(*) from " + dbTableCaches + " where geocode = ?"); - final File[] files = new File(Settings.getStorage()).listFiles(); + final File[] files = LocalStorage.getStorage().listFiles(); final ArrayList<File> toRemove = new ArrayList<File>(files.length); for (final File file : files) { if (file.isDirectory()) { @@ -3071,7 +2977,7 @@ public class cgData { // Delete cache directories for (final String geocode : geocodes) { - cgBase.deleteDirectory(new File(Settings.getStorage() + geocode)); + cgBase.deleteDirectory(LocalStorage.getStorageDir(geocode)); } } diff --git a/main/src/cgeo/geocaching/cgDirectionImg.java b/main/src/cgeo/geocaching/cgDirectionImg.java index c0a37b0..9c26b41 100644 --- a/main/src/cgeo/geocaching/cgDirectionImg.java +++ b/main/src/cgeo/geocaching/cgDirectionImg.java @@ -1,92 +1,28 @@ package cgeo.geocaching; +import cgeo.geocaching.files.LocalStorage; + import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.entity.BufferedHttpEntity; -import org.apache.http.impl.client.DefaultHttpClient; - -import android.util.Log; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; public class cgDirectionImg { public static void getDrawable(String geocode, String code) { - String dirName; - String fileName; - if (StringUtils.isBlank(geocode) || StringUtils.isBlank(code)) { return; } - if (StringUtils.isNotBlank(geocode)) { - dirName = Settings.getStorage() + geocode + "/"; - fileName = Settings.getStorage() + geocode + "/direction.png"; - } else { - return; + final HttpResponse httpResponse = + cgBase.request("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx", new Parameters("k", code), false); + if (httpResponse != null) { + LocalStorage.saveEntityToFile(httpResponse.getEntity(), getDirectionFile(geocode)); } + } - File dir = null; - dir = new File(Settings.getStorage()); - if (dir.exists() == false) { - dir.mkdirs(); - } - dir = new File(dirName); - if (dir.exists() == false) { - dir.mkdirs(); - } - dir = null; - - HttpClient client = null; - HttpGet getMethod = null; - HttpResponse httpResponse = null; - HttpEntity entity = null; - - boolean ok = false; - - for (int i = 0; i < 3; i++) { - if (i > 0) - Log.w(Settings.tag, "cgDirectionImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1)); - - try { - client = new DefaultHttpClient(); - getMethod = new HttpGet("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx?k=" + code); - httpResponse = client.execute(getMethod); - entity = httpResponse.getEntity(); - final BufferedHttpEntity bufferedEntity = new BufferedHttpEntity(entity); - - Log.i(Settings.tag, "[" + entity.getContentLength() + "B] Downloading direction image " + code); - - InputStream is = (InputStream) bufferedEntity.getContent(); - FileOutputStream fos = new FileOutputStream(fileName); - - try { - byte[] buffer = new byte[4096]; - int l; - while ((l = is.read(buffer)) != -1) { - fos.write(buffer, 0, l); - } - ok = true; - fos.flush(); - } catch (IOException e) { - Log.e(Settings.tag, "cgDirectionImg.getDrawable (saving to cache): " + e.toString()); - } finally { - is.close(); - fos.close(); - } - - if (ok) { - break; - } - } catch (Exception e) { - Log.e(Settings.tag, "cgDirectionImg.getDrawable (downloading from web): " + e.toString()); - } - } + public static File getDirectionFile(final String geocode) { + return LocalStorage.getStorageFile(geocode, "direction.png", false); } -} + +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/cgHtmlImg.java b/main/src/cgeo/geocaching/cgHtmlImg.java index 6c10ffa..bf5ef91 100644 --- a/main/src/cgeo/geocaching/cgHtmlImg.java +++ b/main/src/cgeo/geocaching/cgHtmlImg.java @@ -1,13 +1,10 @@ package cgeo.geocaching; import cgeo.geocaching.connector.ConnectorFactory; -import cgeo.geocaching.connector.IConnector; -import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.files.LocalStorage; import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; import org.apache.http.entity.BufferedHttpEntity; import android.app.Activity; @@ -23,8 +20,6 @@ import android.view.Display; import android.view.WindowManager; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; import java.util.Date; @@ -69,134 +64,55 @@ public class cgHtmlImg implements Html.ImageGetter { } @Override - public BitmapDrawable getDrawable(String url) { - if (StringUtils.isBlank(url)) { + public BitmapDrawable getDrawable(final String url) { + // Reject empty and counter images URL + if (StringUtils.isBlank(url) || isCounter(url)) { return null; } - if (isCounter(url)) { - return null; - } - - String urlExt = StringUtils.substringAfterLast(url, "."); - if (urlExt.length() > 0) { - urlExt = "." + urlExt; - } - if (urlExt.length() > 5) { - urlExt = ""; - } - String dirName; - String fileName; - String fileNameSec; - - if (StringUtils.isNotBlank(geocode)) { - dirName = Settings.getStorage() + geocode + "/"; - fileName = Settings.getStorage() + geocode + "/" + CryptUtils.md5(url) + urlExt; - fileNameSec = Settings.getStorageSec() + geocode + "/" + CryptUtils.md5(url) + urlExt; - } else { - dirName = Settings.getStorage() + "_others/"; - fileName = Settings.getStorage() + "_others/" + CryptUtils.md5(url) + urlExt; - fileNameSec = Settings.getStorageSec() + "_others/" + CryptUtils.md5(url) + urlExt; - } - - File dir = null; - dir = new File(Settings.getStorage()); - if (!dir.exists()) { - dir.mkdirs(); - } - dir = new File(dirName); - if (!dir.exists()) { - dir.mkdirs(); - } - dir = null; + final File file = LocalStorage.getStorageFile(geocode, url, true); + final File fileSec = LocalStorage.getStorageSecFile(geocode, url, true); Bitmap imagePre = null; - // load image from cache + + // Load image from cache if (!onlySave) { try { - imagePre = loadCachedImage(fileName); - if (null == imagePre) { - imagePre = loadCachedImage(fileNameSec); + imagePre = loadCachedImage(file); + if (imagePre == null) { + imagePre = loadCachedImage(fileSec); } } catch (Exception e) { Log.w(Settings.tag, "cgHtmlImg.getDrawable (reading cache): " + e.toString()); } } - // download image and save it to the cache + // Download image and save it to the cache if (imagePre == null || onlySave) { - Uri uri = null; + final String absoluteURL = makeAbsoluteURL(url); BufferedHttpEntity bufferedEntity = null; - try { - // check if uri is absolute or not, if not attach geocaching.com hostname and scheme - uri = Uri.parse(url); - - if (!uri.isAbsolute()) { - final IConnector connector = ConnectorFactory.getConnector(geocode); - url = "http://" + connector.getHost() + url; - } - } catch (Exception e) { - Log.e(Settings.tag, "cgHtmlImg.getDrawable (parse URL): " + e.toString()); - } - - if (null != uri) { - for (int i = 0; i < 2; i++) { - if (i > 0) { - Log.w(Settings.tag, "cgHtmlImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1)); - } - - try { - final HttpGet getMethod = new HttpGet(url); - final HttpResponse httpResponse = cgBase.doRequest(getMethod); - if (null != httpResponse) { - final HttpEntity entity = httpResponse.getEntity(); - bufferedEntity = new BufferedHttpEntity(entity); - - setSampleSize(bufferedEntity.getContentLength()); - - final InputStream is = bufferedEntity.getContent(); - try { - imagePre = BitmapFactory.decodeStream(is, null, bfOptions); - } finally { - is.close(); - } - } - - if (null != imagePre) { - break; - } - } catch (Exception e) { - Log.e(Settings.tag, "cgHtmlImg.getDrawable (downloading from web)", e); - } - } - } - - if (save) { + if (absoluteURL != null) { try { - // save to memory/SD cache - if (null != bufferedEntity) { + final HttpResponse httpResponse = cgBase.request(absoluteURL, null, false); + if (httpResponse != null) { + bufferedEntity = new BufferedHttpEntity(httpResponse.getEntity()); + setSampleSize(bufferedEntity.getContentLength()); final InputStream is = bufferedEntity.getContent(); try { - final FileOutputStream fos = new FileOutputStream(fileName); - try { - final byte[] buffer = new byte[4096]; - int l; - while ((l = is.read(buffer)) != -1) { - fos.write(buffer, 0, l); - } - fos.flush(); - } finally { - fos.close(); - } + imagePre = BitmapFactory.decodeStream(is, null, bfOptions); } finally { is.close(); } } - } catch (IOException e) { - Log.e(Settings.tag, "cgHtmlImg.getDrawable (saving to cache)", e); + } catch (Exception e) { + Log.e(Settings.tag, "cgHtmlImg.getDrawable (downloading from web)", e); } } + + if (save) { + LocalStorage.saveEntityToFile(bufferedEntity, file); + } } if (onlySave) { @@ -204,7 +120,7 @@ public class cgHtmlImg implements Html.ImageGetter { } // get image and return - if (null == imagePre) { + if (imagePre == null) { Log.d(Settings.tag, "cgHtmlImg.getDrawable: Failed to obtain image"); if (placement) { @@ -248,12 +164,26 @@ public class cgHtmlImg implements Html.ImageGetter { return image; } - private Bitmap loadCachedImage(final String fileName) { - final File file = new File(fileName); + private final String makeAbsoluteURL(final String url) { + try { + // Check if uri is absolute or not, if not attach the connector hostname + // FIXME: that should also include the scheme + if (Uri.parse(url).isAbsolute()) { + return url; + } else { + return "http://" + ConnectorFactory.getConnector(geocode).getHost() + url; + } + } catch (Exception e) { + Log.e(Settings.tag, "cgHtmlImg.makeAbsoluteURL (parse URL)", e); + return null; + } + } + + private Bitmap loadCachedImage(final File file) { if (file.exists()) { if (reason > 0 || file.lastModified() > (new Date().getTime() - (24 * 60 * 60 * 1000))) { setSampleSize(file.length()); - return BitmapFactory.decodeFile(fileName, bfOptions); + return BitmapFactory.decodeFile(file.getPath(), bfOptions); } } return null; diff --git a/main/src/cgeo/geocaching/cgeoimages.java b/main/src/cgeo/geocaching/cgeoimages.java index fe505c9..9f9a2ce 100644 --- a/main/src/cgeo/geocaching/cgeoimages.java +++ b/main/src/cgeo/geocaching/cgeoimages.java @@ -1,6 +1,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.files.LocalStorage; import org.apache.commons.lang3.StringUtils; @@ -13,7 +14,6 @@ import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Environment; import android.text.Html; import android.util.Log; import android.view.LayoutInflater; @@ -105,8 +105,7 @@ public class cgeoimages extends AbstractActivity { image_view.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { - final String directoryTarget = Environment.getExternalStorageDirectory() + "/" + Settings.cache + "/" + "temp.jpg"; - final File file = new File(directoryTarget); + final File file = LocalStorage.getStorageFile(null, "temp.jpg", false); try { final FileOutputStream fos = new FileOutputStream(file); image.getBitmap().compress(CompressFormat.JPEG, 100, fos); diff --git a/main/src/cgeo/geocaching/cgeosmaps.java b/main/src/cgeo/geocaching/cgeosmaps.java index fd3d6e8..c64da71 100644 --- a/main/src/cgeo/geocaching/cgeosmaps.java +++ b/main/src/cgeo/geocaching/cgeosmaps.java @@ -115,7 +115,7 @@ public class cgeosmaps extends AbstractActivity { for (int level = 1; level <= 5; level++) { try { - Bitmap image = BitmapFactory.decodeFile(Settings.getStorage() + geocode + "/map_" + level); + final Bitmap image = BitmapFactory.decodeFile(StaticMapsProvider.getMapFile(geocode, level).getPath()); if (image != null) { maps.add(image); } @@ -127,7 +127,7 @@ public class cgeosmaps extends AbstractActivity { if (maps.isEmpty()) { for (int level = 1; level <= 5; level++) { try { - Bitmap image = BitmapFactory.decodeFile(Settings.getStorageSec() + geocode + "/map_" + level); + final Bitmap image = BitmapFactory.decodeFile(StaticMapsProvider.getMapFile(geocode, level).getPath()); if (image != null) { maps.add(image); } diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java new file mode 100644 index 0000000..a5e4f85 --- /dev/null +++ b/main/src/cgeo/geocaching/files/LocalStorage.java @@ -0,0 +1,217 @@ +package cgeo.geocaching.files; + +import cgeo.geocaching.Settings; +import cgeo.geocaching.utils.CryptUtils; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; + +import android.os.Environment; +import android.util.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Handle local storage issues on phone and SD card. + * + */ +public class LocalStorage { + + /** + * Return the primary storage cache root (external media if mounted, phone otherwise). + * + * @return the root of the cache directory + */ + public static File getStorage() { + return getStorageSpecific(false); + } + + /** + * Return the primary storage cache root (phone if external media is mounted, external media otherwise). + * + * @return the root of the cache directory + */ + public static File getStorageSec() { + return getStorageSpecific(true); + } + + private static File getStorageSpecific(boolean secondary) { + return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ^ secondary ? + new File(Environment.getExternalStorageDirectory(), Settings.cache) : + new File(new File(new File(Environment.getDataDirectory(), "data"), "cgeo.geocaching"), Settings.cache); + } + + /** + * Get the guessed file extension of an URL. A file extension can contain up-to 4 characters in addition to the dot. + * + * @param url + * the relative or absolute URL + * @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, "."); + if (urlExt.length() > 4) { + return ""; + } else if (urlExt.length() > 0) { + return "." + urlExt; + } + return ""; + } + + /** + * Get the primary storage cache directory for a geocode. The directory and its parents will be created if + * necessary. A null or empty geocode will be replaced by a default value. + * + * @param geocode + * the geocode + * @return the cache directory + */ + public static File getStorageDir(final String geocode) { + return buildStorageDir(getStorage(), geocode); + } + + /** + * Get the secondary storage cache directory for a geocode. The directory and its parents will be created if + * necessary. A null or empty geocode will be replaced by a default value. + * + * @param geocode + * the geocode + * @return the cache directory + */ + public static File getStorageSecDir(final String geocode) { + return buildStorageDir(getStorageSec(), geocode); + } + + private static File buildStorageDir(final File base, final String geocode) { + final File dir = new File(base, StringUtils.defaultIfEmpty(geocode, "_others")); + dir.mkdirs(); + return dir; + } + + /** + * Get the primary file corresponding to a geocode and a file name or an url. If it is an url, an appropriate + * filename will be built by hashing it. The directory structure will be created if needed. + * A null or empty geocode will be replaced by a default value. + * + * @param geocode + * the geocode + * @param fileNameOrUrl + * the file name or url + * @param isUrl + * true if an url was given, false if a file name was given + * @return the file + */ + public static File getStorageFile(final String geocode, final String fileNameOrUrl, final boolean isUrl) { + return buildFile(getStorageDir(geocode), fileNameOrUrl, isUrl); + } + + /** + * Get the secondary file corresponding to a geocode and a file name or an url. If it is an url, an appropriate + * filename will be built by hashing it. The directory structure will be created if needed. + * A null or empty geocode will be replaced by a default value. + * + * @param geocode + * the geocode + * @param fileNameOrUrl + * the file name or url + * @param isUrl + * true if an url was given, false if a file name was given + * @return the file + */ + public static File getStorageSecFile(final String geocode, final String fileNameOrUrl, final boolean isUrl) { + return buildFile(getStorageSecDir(geocode), fileNameOrUrl, isUrl); + } + + private static File buildFile(final File base, final String fileName, final boolean isUrl) { + return new File(base, isUrl ? CryptUtils.md5(fileName) + getExtension(fileName) : fileName); + } + + /** + * Save an HTTP response to a file. + * + * @param entity + * the entity whose content will be saved + * @param targetFile + * the target file, which will be created if necessary + * @return true if the operation was sucessful, false otherwise + */ + public static boolean saveEntityToFile(final HttpEntity entity, final File targetFile) { + if (entity == null) { + return false; + } + + try { + final InputStream is = entity.getContent(); + try { + final FileOutputStream fos = new FileOutputStream(targetFile); + try { + final byte[] buffer = new byte[4096]; + int l; + while ((l = is.read(buffer)) != -1) { + fos.write(buffer, 0, l); + } + fos.flush(); // FIXME: is this really necessary? + return true; + } finally { + fos.close(); + } + } finally { + is.close(); + } + } catch (IOException e) { + Log.e(Settings.tag, "LocalStorage.saveEntityToFile", e); + } + return false; + } + + /** + * Copy a file into another. The directory structure of target file will be created if needed. + * + * @param source + * the source file + * @param destination + * the target file + * @return true if the copy happened without error, false otherwise + */ + public static boolean copy(final File source, final File destination) { + destination.getParentFile().mkdirs(); + + InputStream input; + OutputStream output; + try { + input = new FileInputStream(source); + output = new FileOutputStream(destination); + } catch (FileNotFoundException e) { + Log.e(Settings.tag, "LocalStorage.copy: could not open file", e); + return false; + } + + byte[] buffer = new byte[4096]; + int length; + try { + while ((length = input.read(buffer)) > 0) { + output.write(buffer, 0, length); + } + output.flush(); // FIXME: is that necessary? + } catch (IOException e) { + Log.e(Settings.tag, "LocalStorage.copy: error when copying file", e); + return false; + } + + try { + input.close(); + output.close(); + } catch (IOException e) { + Log.e(Settings.tag, "LocalStorage.copy: could not close file", e); + return false; + } + + return true; + } +} |
