summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/home/ImageLoader.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/home/ImageLoader.java')
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/home/ImageLoader.java164
1 files changed, 164 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/home/ImageLoader.java b/mobile/android/base/java/org/mozilla/gecko/home/ImageLoader.java
new file mode 100644
index 000000000..2bbd82a8d
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/home/ImageLoader.java
@@ -0,0 +1,164 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.home;
+
+import android.content.Context;
+import android.net.Uri;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import com.squareup.picasso.LruCache;
+import com.squareup.picasso.Picasso;
+import com.squareup.picasso.Downloader.Response;
+import com.squareup.picasso.UrlConnectionDownloader;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.mozilla.gecko.distribution.Distribution;
+
+public class ImageLoader {
+ private static final String LOGTAG = "GeckoImageLoader";
+
+ private static final String DISTRIBUTION_SCHEME = "gecko.distribution";
+ private static final String SUGGESTED_SITES_AUTHORITY = "suggestedsites";
+
+ // The order of density factors to try when looking for an image resource
+ // in the distribution directory. It looks for an exact match first (1.0) then
+ // tries to find images with higher density (2.0 and 1.5). If no image is found,
+ // try a lower density (0.5). See loadDistributionImage().
+ private static final float[] densityFactors = new float[] { 1.0f, 2.0f, 1.5f, 0.5f };
+
+ private static enum Density {
+ MDPI,
+ HDPI,
+ XHDPI,
+ XXHDPI;
+
+ @Override
+ public String toString() {
+ return super.toString().toLowerCase();
+ }
+ }
+
+ // Picasso instance and LruCache lrucache are protected by synchronization.
+ private static Picasso instance;
+ private static LruCache lrucache;
+
+ public static synchronized Picasso with(Context context) {
+ if (instance == null) {
+ lrucache = new LruCache(context);
+ Picasso.Builder builder = new Picasso.Builder(context).memoryCache(lrucache);
+
+ final Distribution distribution = Distribution.getInstance(context.getApplicationContext());
+ builder.downloader(new ImageDownloader(context, distribution));
+ instance = builder.build();
+ }
+
+ return instance;
+ }
+
+ public static synchronized void clearLruCache() {
+ if (lrucache != null) {
+ lrucache.evictAll();
+ }
+ }
+
+ /**
+ * Custom Downloader built on top of Picasso's UrlConnectionDownloader
+ * that supports loading images from custom URIs.
+ */
+ public static class ImageDownloader extends UrlConnectionDownloader {
+ private final Context context;
+ private final Distribution distribution;
+
+ public ImageDownloader(Context context, Distribution distribution) {
+ super(context);
+ this.context = context;
+ this.distribution = distribution;
+ }
+
+ private Density getDensity(float factor) {
+ final DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ final float densityDpi = dm.densityDpi * factor;
+
+ if (densityDpi >= DisplayMetrics.DENSITY_XXHIGH) {
+ return Density.XXHDPI;
+ } else if (densityDpi >= DisplayMetrics.DENSITY_XHIGH) {
+ return Density.XHDPI;
+ } else if (densityDpi >= DisplayMetrics.DENSITY_HIGH) {
+ return Density.HDPI;
+ }
+
+ // Fallback to mdpi, no need to handle ldpi.
+ return Density.MDPI;
+ }
+
+ @Override
+ public Response load(Uri uri, boolean localCacheOnly) throws IOException {
+ final String scheme = uri.getScheme();
+ if (DISTRIBUTION_SCHEME.equals(scheme)) {
+ return loadDistributionImage(uri);
+ }
+
+ return super.load(uri, localCacheOnly);
+ }
+
+ private static String getPathForDensity(String basePath, Density density,
+ String filename) {
+ final File dir = new File(basePath, density.toString());
+ return String.format("%s/%s.png", dir.toString(), filename);
+ }
+
+ /**
+ * Handle distribution URIs in Picasso. The expected format is:
+ *
+ * gecko.distribution://<basepath>/<imagename>
+ *
+ * Which will look for the following file in the distribution:
+ *
+ * <distribution-root-dir>/<basepath>/<device-density>/<imagename>.png
+ */
+ private Response loadDistributionImage(Uri uri) throws IOException {
+ // Eliminate the leading '//'
+ final String ssp = uri.getSchemeSpecificPart().substring(2);
+
+ final String filename;
+ final String basePath;
+
+ final int slashIndex = ssp.lastIndexOf('/');
+ if (slashIndex == -1) {
+ filename = ssp;
+ basePath = "";
+ } else {
+ filename = ssp.substring(slashIndex + 1);
+ basePath = ssp.substring(0, slashIndex);
+ }
+
+ Set<Density> triedDensities = EnumSet.noneOf(Density.class);
+
+ for (int i = 0; i < densityFactors.length; i++) {
+ final Density density = getDensity(densityFactors[i]);
+ if (!triedDensities.add(density)) {
+ continue;
+ }
+
+ final String path = getPathForDensity(basePath, density, filename);
+ Log.d(LOGTAG, "Trying to load image from distribution " + path);
+
+ final File f = distribution.getDistributionFile(path);
+ if (f != null) {
+ return new Response(new FileInputStream(f), true);
+ }
+ }
+
+ throw new ResponseException("Couldn't find suggested site image in distribution");
+ }
+ }
+}