aboutsummaryrefslogtreecommitdiffstats
path: root/main/src
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2011-10-06 23:33:21 +0200
committerSamuel Tardieu <sam@rfc1149.net>2011-10-06 23:33:21 +0200
commitcf8a6acc34f211fe1fb790a57befa86a835585dd (patch)
tree8ebcfc8c38cf67cd745db24de98e41b8ef2d1b4a /main/src
parentf8d30878a368895ce030099287c85836a446a66e (diff)
downloadcgeo-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.java20
-rw-r--r--main/src/cgeo/geocaching/StaticMapsProvider.java98
-rw-r--r--main/src/cgeo/geocaching/cgCacheListAdapter.java2
-rw-r--r--main/src/cgeo/geocaching/cgData.java138
-rw-r--r--main/src/cgeo/geocaching/cgDirectionImg.java86
-rw-r--r--main/src/cgeo/geocaching/cgHtmlImg.java156
-rw-r--r--main/src/cgeo/geocaching/cgeoimages.java5
-rw-r--r--main/src/cgeo/geocaching/cgeosmaps.java4
-rw-r--r--main/src/cgeo/geocaching/files/LocalStorage.java217
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;
+ }
+}