aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/network/HtmlImage.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/network/HtmlImage.java')
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java232
1 files changed, 232 insertions, 0 deletions
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
new file mode 100644
index 0000000..b3511e3
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -0,0 +1,232 @@
+package cgeo.geocaching.network;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.files.LocalStorage;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.entity.BufferedHttpEntity;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.text.Html;
+import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+
+public class HtmlImage implements Html.ImageGetter {
+
+ private static final String[] BLOCKED = new String[] {
+ "gccounter.de",
+ "gccounter.com",
+ "cachercounter/?",
+ "gccounter/imgcount.php",
+ "flagcounter.com",
+ "compteur-blog.net",
+ "counter.digits.com"
+ };
+ final private Context context;
+ final private String geocode;
+ /**
+ * on error: return large error image, if <code>true</code>, otherwise empty 1x1 image
+ */
+ final private boolean returnErrorImage;
+ final private int reason;
+ final private boolean onlySave;
+ final private boolean save;
+ final private BitmapFactory.Options bfOptions;
+ final private int maxWidth;
+ final private int maxHeight;
+
+ public HtmlImage(final Context context, final String geocode, final boolean returnErrorImage, final int reason, final boolean onlySave) {
+ this(context, geocode, returnErrorImage, reason, onlySave, true);
+ }
+
+ public HtmlImage(final Context contextIn, final String geocode, final boolean returnErrorImage, final int reason, final boolean onlySave, final boolean save) {
+ this.context = contextIn;
+ this.geocode = geocode;
+ this.returnErrorImage = returnErrorImage;
+ this.reason = reason;
+ this.onlySave = onlySave;
+ this.save = save;
+
+ bfOptions = new BitmapFactory.Options();
+ bfOptions.inTempStorage = new byte[16 * 1024];
+
+ final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ this.maxWidth = display.getWidth() - 25;
+ this.maxHeight = display.getHeight() - 25;
+ }
+
+ @Override
+ public BitmapDrawable getDrawable(final String url) {
+ // Reject empty and counter images URL
+ if (StringUtils.isBlank(url) || isCounter(url)) {
+ return null;
+ }
+
+ Bitmap imagePre = null;
+
+ // Load image from cache
+ if (!onlySave) {
+ imagePre = loadImageFromStorage(url);
+ }
+
+ // Download image and save it to the cache
+ if (imagePre == null || onlySave) {
+ final String absoluteURL = makeAbsoluteURL(url);
+ BufferedHttpEntity bufferedEntity = null;
+
+ if (absoluteURL != null) {
+ try {
+ final HttpResponse httpResponse = cgBase.request(absoluteURL, null, false);
+ if (httpResponse != null) {
+ bufferedEntity = new BufferedHttpEntity(httpResponse.getEntity());
+ }
+ } catch (Exception e) {
+ Log.e(Settings.tag, "HtmlImage.getDrawable (downloading from web)", e);
+ }
+ }
+
+ if (save) {
+ final File file = LocalStorage.getStorageFile(geocode, url, true);
+ LocalStorage.saveEntityToFile(bufferedEntity, file);
+ } else {
+ setSampleSize(bufferedEntity.getContentLength());
+ InputStream is;
+ try {
+ is = bufferedEntity.getContent();
+ imagePre = BitmapFactory.decodeStream(is, null, bfOptions);
+ } catch (IOException e) {
+ Log.e(Settings.tag, "HtmlImage.getDrawable (decoding image)", e);
+ }
+ }
+ }
+
+ if (onlySave) {
+ return null;
+ }
+
+ // now load the newly downloaded image
+ if (imagePre == null) {
+ imagePre = loadImageFromStorage(url);
+ }
+
+ // get image and return
+ if (imagePre == null) {
+ Log.d(Settings.tag, "HtmlImage.getDrawable: Failed to obtain image");
+
+ if (returnErrorImage) {
+ imagePre = BitmapFactory.decodeResource(context.getResources(), R.drawable.image_not_loaded);
+ } else {
+ imagePre = BitmapFactory.decodeResource(context.getResources(), R.drawable.image_no_placement);
+ }
+ }
+
+ final int imgWidth = imagePre.getWidth();
+ final int imgHeight = imagePre.getHeight();
+
+ int width;
+ int height;
+
+ if (imgWidth > maxWidth || imgHeight > maxHeight) {
+ final double ratio = Math.min((double) maxHeight / (double) imgHeight, (double) maxWidth / (double) imgWidth);
+ width = (int) Math.ceil(imgWidth * ratio);
+ height = (int) Math.ceil(imgHeight * ratio);
+
+ try {
+ imagePre = Bitmap.createScaledBitmap(imagePre, width, height, true);
+ } catch (Exception e) {
+ Log.d(Settings.tag, "HtmlImage.getDrawable: Failed to scale image");
+ return null;
+ }
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+
+ final BitmapDrawable image = new BitmapDrawable(imagePre);
+ image.setBounds(new Rect(0, 0, width, height));
+
+ return image;
+ }
+
+ private Bitmap loadImageFromStorage(final String url) {
+ try {
+ final File file = LocalStorage.getStorageFile(geocode, url, true);
+ final Bitmap image = loadCachedImage(file);
+ if (image != null) {
+ return image;
+ }
+ final File fileSec = LocalStorage.getStorageSecFile(geocode, url, true);
+ return loadCachedImage(fileSec);
+ } catch (Exception e) {
+ Log.w(Settings.tag, "HtmlImage.getDrawable (reading cache): " + e.toString());
+ }
+ return null;
+ }
+
+ 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 {
+ final String host = ConnectorFactory.getConnector(geocode).getHost();
+ if (StringUtils.isNotEmpty(host)) {
+ return "http://" + host + url;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(Settings.tag, "HtmlImage.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(file.getPath(), bfOptions);
+ }
+ }
+ return null;
+ }
+
+ private void setSampleSize(final long imageSize) {
+ // large images will be downscaled on input to save memory
+ if (imageSize > (6 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 48;
+ } else if (imageSize > (4 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 16;
+ } else if (imageSize > (2 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 10;
+ } else if (imageSize > (1 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 6;
+ } else if (imageSize > (0.5 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 2;
+ }
+ }
+
+ private static boolean isCounter(final String url) {
+ for (String entry : BLOCKED) {
+ if (StringUtils.containsIgnoreCase(url, entry)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}