Bug 1290014 - Remove obsolete code. r=ahunt,Grisha
authorSebastian Kaspari <s.kaspari@gmail.com>
Wed, 17 Aug 2016 17:27:06 +0200
changeset 312469 a73dcd57f417301ee649a6777c3ccdc027d7eb01
parent 312468 a803f062653e7554b50fc1d3b145fe71ec5447e3
child 312470 c588732a368ebce977fd6730bcb73672529807cd
push id20447
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 20:36:44 +0000
treeherderfx-team@969397f22187 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahunt, Grisha
bugs1290014
milestone51.0a1
Bug 1290014 - Remove obsolete code. r=ahunt,Grisha Most of the code in the favicons package is now obsolete and can be removed. Most of this code still exists in the icons package (in smaller chunks). MozReview-Commit-ID: 6J4pgd5doNt
mobile/android/base/geckoview.ddf
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/db/BrowserDB.java
mobile/android/base/java/org/mozilla/gecko/db/LocalBrowserDB.java
mobile/android/base/java/org/mozilla/gecko/db/LocalURLMetadata.java
mobile/android/base/java/org/mozilla/gecko/db/StubBrowserDB.java
mobile/android/base/java/org/mozilla/gecko/favicons/FaviconGenerator.java
mobile/android/base/java/org/mozilla/gecko/favicons/Favicons.java
mobile/android/base/java/org/mozilla/gecko/favicons/LoadFaviconTask.java
mobile/android/base/java/org/mozilla/gecko/favicons/OnFaviconLoadedListener.java
mobile/android/base/java/org/mozilla/gecko/favicons/RemoteFavicon.java
mobile/android/base/java/org/mozilla/gecko/favicons/cache/FaviconCache.java
mobile/android/base/java/org/mozilla/gecko/favicons/cache/FaviconCacheElement.java
mobile/android/base/java/org/mozilla/gecko/favicons/cache/FaviconsForURL.java
mobile/android/base/java/org/mozilla/gecko/favicons/decoders/FaviconDecoder.java
mobile/android/base/java/org/mozilla/gecko/favicons/decoders/ICODecoder.java
mobile/android/base/java/org/mozilla/gecko/favicons/decoders/LoadFaviconResult.java
mobile/android/base/java/org/mozilla/gecko/home/TwoLinePageRow.java
mobile/android/base/java/org/mozilla/gecko/icons/loader/ContentProviderLoader.java
mobile/android/base/java/org/mozilla/gecko/icons/loader/DataUriLoader.java
mobile/android/base/java/org/mozilla/gecko/icons/loader/IconDownloader.java
mobile/android/base/java/org/mozilla/gecko/icons/loader/LegacyLoader.java
mobile/android/base/java/org/mozilla/gecko/promotion/HomeScreenPrompt.java
mobile/android/base/moz.build
mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconDownloader.java
--- a/mobile/android/base/geckoview.ddf
+++ b/mobile/android/base/geckoview.ddf
@@ -54,18 +54,17 @@ show allResults
   org.mozilla.gecko.Tab \
   org.mozilla.gecko.Tabs \
   org.mozilla.gecko.Telemetry \
   org.mozilla.gecko.TelemetryContract \
   org.mozilla.gecko.ThumbnailHelper \
   org.mozilla.gecko.db.BrowserDB \
   org.mozilla.gecko.db.LocalBrowserDB \
   org.mozilla.gecko.distribution.Distribution \
-  org.mozilla.gecko.favicons.Favicons \
-  org.mozilla.gecko.favicons.OnFaviconLoadedListener
+  org.mozilla.gecko.icons.*
 
 [main] = org.mozilla.gecko.* excluding [lib] [middle]
 
 check sets [lib] [middle] [main]
 
 # Bug 1107134: it appears that Classycle can be fooled if the Java
 # compiler inlines a constant from [main] into [lib].  That is, [main]
 # really does depend on [lib] but Classycle only sees the dependency
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.UrlAnnotations;
-import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.FullScreenState;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.health.HealthRecorder;
 import org.mozilla.gecko.health.SessionInformation;
 import org.mozilla.gecko.health.StubbedHealthRecorder;
 import org.mozilla.gecko.home.HomeConfig.PanelType;
 import org.mozilla.gecko.icons.IconCallback;
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserDB.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserDB.java
@@ -129,25 +129,23 @@ public interface BrowserDB {
 
     /**
      * Get the favicon from the database, if any, associated with the given favicon URL. (That is,
      * the URL of the actual favicon image, not the URL of the page with which the favicon is associated.)
      * @param cr The ContentResolver to use.
      * @param faviconURL The URL of the favicon to fetch from the database.
      * @return The decoded Bitmap from the database, if any. null if none is stored.
      */
-    public abstract LoadFaviconResult getFaviconForUrl(ContentResolver cr, String faviconURL);
+    public abstract LoadFaviconResult getFaviconForUrl(Context context, ContentResolver cr, String faviconURL);
 
     /**
      * Try to find a usable favicon URL in the history or bookmarks table.
      */
     public abstract String getFaviconURLFromPageURL(ContentResolver cr, String uri);
 
-    public abstract void updateFaviconForUrl(ContentResolver cr, String pageUri, byte[] encodedFavicon, String faviconUri);
-
     public abstract byte[] getThumbnailForUrl(ContentResolver cr, String uri);
     public abstract void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail);
 
     /**
      * Query for non-null thumbnails matching the provided <code>urls</code>.
      * The returned cursor will have no more than, but possibly fewer than,
      * the requested number of thumbnails.
      *
@@ -163,21 +161,16 @@ public interface BrowserDB {
             Collection<ContentProviderOperation> operations, String url,
             String title, long date, int visits);
 
     public abstract void updateBookmarkInBatch(ContentResolver cr,
             Collection<ContentProviderOperation> operations, String url,
             String title, String guid, long parent, long added, long modified,
             long position, String keyword, int type);
 
-    public abstract void updateFaviconInBatch(ContentResolver cr,
-            Collection<ContentProviderOperation> operations, String url,
-            String faviconUrl, String faviconGuid, byte[] data);
-
-
     public abstract void pinSite(ContentResolver cr, String url, String title, int position);
     public abstract void unpinSite(ContentResolver cr, int position);
 
     public abstract boolean hideSuggestedSite(String url);
     public abstract void setSuggestedSites(SuggestedSites suggestedSites);
     public abstract SuggestedSites getSuggestedSites();
     public abstract boolean hasSuggestedImageUrl(String url);
     public abstract String getSuggestedImageUrlForUrl(String url);
--- a/mobile/android/base/java/org/mozilla/gecko/db/LocalBrowserDB.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/LocalBrowserDB.java
@@ -61,19 +61,22 @@ import android.support.annotation.CheckR
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.content.CursorLoader;
 import android.text.TextUtils;
 import android.util.Log;
 import org.mozilla.gecko.util.IOUtils;
 
 import static org.mozilla.gecko.util.IOUtils.ConsumedInputStream;
-import static org.mozilla.gecko.favicons.LoadFaviconTask.DEFAULT_FAVICON_BUFFER_SIZE;
 
 public class LocalBrowserDB implements BrowserDB {
+    // The default size of the buffer to use for downloading Favicons in the event no size is given
+    // by the server.
+    public static final int DEFAULT_FAVICON_BUFFER_SIZE_BYTES = 25000;
+
     private static final String LOGTAG = "GeckoLocalBrowserDB";
 
     // Calculate this once, at initialization. isLoggable is too expensive to
     // have in-line in each log call.
     private static final boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG);
     protected static void debug(String message) {
         if (logDebug) {
             Log.d(LOGTAG, message);
@@ -509,27 +512,27 @@ public class LocalBrowserDB implements B
         final int faviconId = getFaviconId(name);
         if (faviconId == FAVICON_ID_NOT_FOUND) {
             return null;
         }
 
         final String bitmapPath = GeckoJarReader.getJarURL(context, context.getString(faviconId));
         final InputStream iStream = GeckoJarReader.getStream(context, bitmapPath);
 
-        return IOUtils.readFully(iStream, DEFAULT_FAVICON_BUFFER_SIZE);
+        return IOUtils.readFully(iStream, DEFAULT_FAVICON_BUFFER_SIZE_BYTES);
     }
 
     private static ConsumedInputStream getDefaultFaviconFromDrawable(Context context, String name) {
         int faviconId = getFaviconId(name);
         if (faviconId == FAVICON_ID_NOT_FOUND) {
             return null;
         }
 
         InputStream iStream = context.getResources().openRawResource(faviconId);
-        return IOUtils.readFully(iStream, DEFAULT_FAVICON_BUFFER_SIZE);
+        return IOUtils.readFully(iStream, DEFAULT_FAVICON_BUFFER_SIZE_BYTES);
     }
 
     // Invalidate cached data
     @Override
     public void invalidate() {
         mDesktopBookmarksExist = null;
     }
 
@@ -1183,17 +1186,17 @@ public class LocalBrowserDB implements B
     /**
      * Get the favicon from the database, if any, associated with the given favicon URL. (That is,
      * the URL of the actual favicon image, not the URL of the page with which the favicon is associated.)
      * @param cr The ContentResolver to use.
      * @param faviconURL The URL of the favicon to fetch from the database.
      * @return The decoded Bitmap from the database, if any. null if none is stored.
      */
     @Override
-    public LoadFaviconResult getFaviconForUrl(ContentResolver cr, String faviconURL) {
+    public LoadFaviconResult getFaviconForUrl(Context context, ContentResolver cr, String faviconURL) {
         final Cursor c = cr.query(mFaviconsUriWithProfile,
                                   new String[] { Favicons.DATA },
                                   Favicons.URL + " = ? AND " + Favicons.DATA + " IS NOT NULL",
                                   new String[] { faviconURL },
                                   null);
 
         boolean shouldDelete = false;
         byte[] b = null;
@@ -1224,17 +1227,17 @@ public class LocalBrowserDB implements B
                 // Do nothing.
             }
         }
 
         if (b == null) {
             return null;
         }
 
-        return FaviconDecoder.decodeFavicon(b);
+        return FaviconDecoder.decodeFavicon(context, b);
     }
 
     /**
      * Try to find a usable favicon URL in the history or bookmarks table.
      */
     @Override
     public String getFaviconURLFromPageURL(ContentResolver cr, String uri) {
         // Check first in the history table.
@@ -1282,90 +1285,16 @@ public class LocalBrowserDB implements B
         if (mSuggestedSites == null) {
             return false;
         }
 
         return mSuggestedSites.hideSite(url);
     }
 
     @Override
-    public void updateFaviconForUrl(ContentResolver cr, String pageUri,
-            byte[] encodedFavicon, String faviconUri) {
-        ContentValues values = new ContentValues();
-        values.put(Favicons.URL, faviconUri);
-        values.put(Favicons.PAGE_URL, pageUri);
-        values.put(Favicons.DATA, encodedFavicon);
-
-        // Update or insert
-        Uri faviconsUri = withDeleted(mFaviconsUriWithProfile).buildUpon().
-                appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
-
-        final int updated = cr.update(faviconsUri,
-                                      values,
-                                      Favicons.URL + " = ?",
-                                      new String[] { faviconUri });
-
-        if (updated == 0) {
-            return;
-        }
-
-        // After writing the encodedFavicon, ensure that the favicon_id in both the bookmark and
-        // history tables are also up-to-date.
-        final int id = getIDForFaviconURL(cr, faviconUri);
-        if (id == FAVICON_ID_NOT_FOUND) {
-            return;
-        }
-
-        updateHistoryAndBookmarksFaviconID(cr, pageUri, id);
-    }
-
-    /**
-     * Locates and returns the favicon ID of a target URL as an Integer.
-     */
-    private Integer getIDForFaviconURL(ContentResolver cr, String faviconURL) {
-        final Cursor c = cr.query(mFaviconsUriWithProfile,
-                                  new String[] { Favicons._ID },
-                                  Favicons.URL + " = ? AND " + Favicons.DATA + " IS NOT NULL",
-                                  new String[] { faviconURL },
-                                  null);
-
-        try {
-            final int col = c.getColumnIndexOrThrow(Favicons._ID);
-            if (c.moveToFirst() && !c.isNull(col)) {
-                return c.getInt(col);
-            }
-
-            // IDs can be negative, so we return a sentinel value indicating "not found".
-            return FAVICON_ID_NOT_FOUND;
-        } finally {
-            c.close();
-        }
-    }
-
-    /**
-     * Update the favicon ID in the history and bookmark tables after a new
-     * favicon table entry is added.
-     */
-    private void updateHistoryAndBookmarksFaviconID(ContentResolver cr, String pageURL, int id) {
-        final ContentValues bookmarkValues = new ContentValues();
-        bookmarkValues.put(Bookmarks.FAVICON_ID, id);
-        cr.update(mBookmarksUriWithProfile,
-                  bookmarkValues,
-                  Bookmarks.URL + " = ?",
-                  new String[] { pageURL });
-
-        final ContentValues historyValues = new ContentValues();
-        historyValues.put(History.FAVICON_ID, id);
-        cr.update(mHistoryUriWithProfile,
-                  historyValues,
-                  History.URL + " = ?",
-                  new String[] { pageURL });
-    }
-
-    @Override
     public void updateThumbnailForUrl(ContentResolver cr, String uri,
             BitmapDrawable thumbnail) {
         // If a null thumbnail was passed in, delete the stored thumbnail for this url.
         if (thumbnail == null) {
             cr.delete(mThumbnailsUriWithProfile, Thumbnails.URL + " == ?", new String[] { uri });
             return;
         }
 
@@ -1674,40 +1603,16 @@ public class LocalBrowserDB implements B
         }
         builder.withValues(values);
 
         // Queue the operation
         operations.add(builder.build());
     }
 
     @Override
-    public void updateFaviconInBatch(ContentResolver cr,
-                                     Collection<ContentProviderOperation> operations,
-                                     String url, String faviconUrl,
-                                     String faviconGuid, byte[] data) {
-        ContentValues values = new ContentValues();
-        values.put(Favicons.DATA, data);
-        values.put(Favicons.PAGE_URL, url);
-        if (faviconUrl != null) {
-            values.put(Favicons.URL, faviconUrl);
-        }
-
-        // Update or insert
-        Uri faviconsUri = withDeleted(mFaviconsUriWithProfile).buildUpon().
-            appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
-        // Update or insert
-        ContentProviderOperation.Builder builder =
-            ContentProviderOperation.newUpdate(faviconsUri);
-        builder.withValues(values);
-        builder.withSelection(Favicons.PAGE_URL + " = ?", new String[] { url });
-        // Queue the operation
-        operations.add(builder.build());
-    }
-
-    @Override
     public void pinSite(ContentResolver cr, String url, String title, int position) {
         ContentValues values = new ContentValues();
         final long now = System.currentTimeMillis();
         values.put(Bookmarks.TITLE, title);
         values.put(Bookmarks.URL, url);
         values.put(Bookmarks.PARENT, Bookmarks.FIXED_PINNED_LIST_ID);
         values.put(Bookmarks.DATE_MODIFIED, now);
         values.put(Bookmarks.POSITION, position);
--- a/mobile/android/base/java/org/mozilla/gecko/db/LocalURLMetadata.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/LocalURLMetadata.java
@@ -13,17 +13,17 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.favicons.Favicons;
+import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
 import android.util.Log;
 import android.util.LruCache;
@@ -80,17 +80,17 @@ public class LocalURLMetadata implements
 
                 Iterator<String> keys = icons.keys();
 
                 ArrayList<Integer> sizes = new ArrayList<Integer>(icons.length());
                 while (keys.hasNext()) {
                     sizes.add(new Integer(keys.next()));
                 }
 
-                final int bestSize = Favicons.selectBestSizeFromList(sizes, preferredSize);
+                final int bestSize = LoadFaviconResult.selectBestSizeFromList(sizes, preferredSize);
                 final String iconURL = icons.getString(Integer.toString(bestSize));
 
                 data.put(URLMetadataTable.TOUCH_ICON_COLUMN, iconURL);
             }
         } catch (JSONException e) {
             Log.w(LOGTAG, "Exception processing touchIconList for LocalURLMetadata; ignoring.", e);
         }
 
--- a/mobile/android/base/java/org/mozilla/gecko/db/StubBrowserDB.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/StubBrowserDB.java
@@ -273,28 +273,24 @@ public class StubBrowserDB implements Br
 
     public void registerBookmarkObserver(ContentResolver cr, ContentObserver observer) {
     }
 
     @RobocopTarget
     public void updateBookmark(ContentResolver cr, int id, String uri, String title, String keyword) {
     }
 
-    public LoadFaviconResult getFaviconForUrl(ContentResolver cr, String faviconURL) {
+    public LoadFaviconResult getFaviconForUrl(Context context, ContentResolver cr, String faviconURL) {
         return null;
     }
 
     public String getFaviconURLFromPageURL(ContentResolver cr, String uri) {
         return null;
     }
 
-    public void updateFaviconForUrl(ContentResolver cr, String pageUri,
-                                    byte[] encodedFavicon, String faviconUri) {
-    }
-
     public boolean hideSuggestedSite(String url) {
         return false;
     }
 
     public void updateThumbnailForUrl(ContentResolver cr, String uri,
                                       BitmapDrawable thumbnail) {
     }
 
@@ -320,22 +316,16 @@ public class StubBrowserDB implements Br
     public void updateBookmarkInBatch(ContentResolver cr,
                                       Collection<ContentProviderOperation> operations,
                                       String url, String title, String guid,
                                       long parent, long added,
                                       long modified, long position,
                                       String keyword, int type) {
     }
 
-    public void updateFaviconInBatch(ContentResolver cr,
-                                     Collection<ContentProviderOperation> operations,
-                                     String url, String faviconUrl,
-                                     String faviconGuid, byte[] data) {
-    }
-
     public void pinSite(ContentResolver cr, String url, String title, int position) {
     }
 
     public void unpinSite(ContentResolver cr, int position) {
     }
 
     @RobocopTarget
     public Cursor getBookmarkForUrl(ContentResolver cr, String url) {
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/FaviconGenerator.java
+++ b/mobile/android/base/java/org/mozilla/gecko/favicons/FaviconGenerator.java
@@ -59,34 +59,16 @@ public class FaviconGenerator {
 
         private IconWithColor(Bitmap bitmap, int color) {
             this.bitmap = bitmap;
             this.color = color;
         }
     }
 
     /**
-     * Asynchronously generate default favicon for the given page URL.
-     */
-    public static void generate(final Context context, final String pageURL, final OnFaviconLoadedListener listener) {
-        ThreadUtils.postToBackgroundThread(new Runnable() {
-            @Override
-            public void run() {
-                final Bitmap bitmap = generate(context, pageURL).bitmap;
-                ThreadUtils.postToUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        listener.onFaviconLoaded(pageURL, null, bitmap);
-                    }
-                });
-            }
-        });
-    }
-
-    /**
      * Generate default favicon for the given page URL.
      */
     public static IconWithColor generate(Context context, String pageURL) {
         final Resources resources = context.getResources();
         final int widthAndHeight = resources.getDimensionPixelSize(R.dimen.favicon_bg);
         final int roundedCorners = resources.getDimensionPixelOffset(R.dimen.favicon_corner_radius);
 
         final Bitmap favicon = Bitmap.createBitmap(widthAndHeight, widthAndHeight, Bitmap.Config.ARGB_8888);
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/Favicons.java
+++ /dev/null
@@ -1,664 +0,0 @@
-/* -*- 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.favicons;
-
-import android.graphics.drawable.Drawable;
-import org.mozilla.gecko.AboutPages;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.Tab;
-import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.URLMetadataTable;
-import org.mozilla.gecko.favicons.cache.FaviconCache;
-import org.mozilla.gecko.util.GeckoJarReader;
-import org.mozilla.gecko.util.NonEvictingLruCache;
-import org.mozilla.gecko.util.StringUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class Favicons {
-    private static final String LOGTAG = "GeckoFavicons";
-
-    public enum LoadType {
-        PRIVILEGED,
-        UNPRIVILEGED
-    }
-
-    // A magic URL representing the app's own favicon, used for about: pages.
-    private static final String BUILT_IN_FAVICON_URL = "about:favicon";
-
-    // A magic URL representing the app's search favicon, used for about:home.
-    private static final String BUILT_IN_SEARCH_URL = "about:search";
-
-    // Size of the favicon bitmap cache, in bytes (Counting payload only).
-    public static final int FAVICON_CACHE_SIZE_BYTES = 512 * 1024;
-
-    // Number of URL mappings from page URL to Favicon URL to cache in memory.
-    public static final int NUM_PAGE_URL_MAPPINGS_TO_STORE = 128;
-
-    public static final int NOT_LOADING  = 0;
-    public static final int LOADED       = 1;
-
-    // The default Favicon to show if no other can be found.
-    public static Bitmap defaultFavicon;
-
-    // The density-adjusted default Favicon dimensions.
-    public static int defaultFaviconSize;
-
-    // The density-adjusted maximum Favicon dimensions.
-    public static int largestFaviconSize;
-
-    // The density-adjusted desired size for a browser-toolbar favicon.
-    public static int browserToolbarFaviconSize;
-
-    // Used to prevent multiple-initialisation.
-    public static final AtomicBoolean isInitialized = new AtomicBoolean(false);
-
-    // Executor for long-running Favicon Tasks.
-    public static final ExecutorService longRunningExecutor = Executors.newSingleThreadExecutor();
-
-    private static final SparseArray<LoadFaviconTask> loadTasks = new SparseArray<>();
-
-    // Cache to hold mappings between page URLs and Favicon URLs. Used to avoid going to the DB when
-    // doing so is not necessary.
-    private static final NonEvictingLruCache<String, String> pageURLMappings = new NonEvictingLruCache<>(NUM_PAGE_URL_MAPPINGS_TO_STORE);
-
-    // Mime types of things we are capable of decoding.
-    private static final HashSet<String> sDecodableMimeTypes = new HashSet<>();
-
-    // Mime types of things we are both capable of decoding and are container formats (May contain
-    // multiple different sizes of image)
-    private static final HashSet<String> sContainerMimeTypes = new HashSet<>();
-    static {
-        // MIME types extracted from http://filext.com - ostensibly all in-use mime types for the
-        // corresponding formats.
-        // ICO
-        sContainerMimeTypes.add("image/vnd.microsoft.icon");
-        sContainerMimeTypes.add("image/ico");
-        sContainerMimeTypes.add("image/icon");
-        sContainerMimeTypes.add("image/x-icon");
-        sContainerMimeTypes.add("text/ico");
-        sContainerMimeTypes.add("application/ico");
-
-        // Add supported container types to the set of supported types.
-        sDecodableMimeTypes.addAll(sContainerMimeTypes);
-
-        // PNG
-        sDecodableMimeTypes.add("image/png");
-        sDecodableMimeTypes.add("application/png");
-        sDecodableMimeTypes.add("application/x-png");
-
-        // GIF
-        sDecodableMimeTypes.add("image/gif");
-
-        // JPEG
-        sDecodableMimeTypes.add("image/jpeg");
-        sDecodableMimeTypes.add("image/jpg");
-        sDecodableMimeTypes.add("image/pipeg");
-        sDecodableMimeTypes.add("image/vnd.swiftview-jpeg");
-        sDecodableMimeTypes.add("application/jpg");
-        sDecodableMimeTypes.add("application/x-jpg");
-
-        // BMP
-        sDecodableMimeTypes.add("application/bmp");
-        sDecodableMimeTypes.add("application/x-bmp");
-        sDecodableMimeTypes.add("application/x-win-bitmap");
-        sDecodableMimeTypes.add("image/bmp");
-        sDecodableMimeTypes.add("image/x-bmp");
-        sDecodableMimeTypes.add("image/x-bitmap");
-        sDecodableMimeTypes.add("image/x-xbitmap");
-        sDecodableMimeTypes.add("image/x-win-bitmap");
-        sDecodableMimeTypes.add("image/x-windows-bitmap");
-        sDecodableMimeTypes.add("image/x-ms-bitmap");
-        sDecodableMimeTypes.add("image/x-ms-bmp");
-        sDecodableMimeTypes.add("image/ms-bmp");
-    }
-
-    public static String getFaviconURLForPageURLFromCache(String pageURL) {
-        return pageURLMappings.get(pageURL);
-    }
-
-    /**
-     * Insert the given pageUrl->faviconUrl mapping into the memory cache of such mappings.
-     * Useful for short-circuiting local database access.
-     */
-    public static void putFaviconURLForPageURLInCache(String pageURL, String faviconURL) {
-        pageURLMappings.put(pageURL, faviconURL);
-    }
-
-    private static FaviconCache faviconsCache;
-
-    /**
-     * Select the closest icon size from a list of icon sizes.
-     * We just find the first icon that is larger than the preferred size if available, or otherwise select the
-     * largest icon (if all icons are smaller than the preferred size).
-     *
-     * @return The closes icon size, or -1 if no sizes are supplied.
-     */
-    public static int selectBestSizeFromList(final List<Integer> sizes, final int preferredSize) {
-        Collections.sort(sizes);
-
-        for (int size : sizes) {
-            if (size >= preferredSize) {
-                return size;
-            }
-        }
-
-        // If all icons are smaller than the preferred size then we don't have an icon
-        // selected yet, therefore just take the largest (last) icon.
-        if (sizes.size() > 0) {
-            return sizes.get(sizes.size() - 1);
-        } else {
-            // This isn't ideal, however current code assumes this as an error value for now.
-            return -1;
-        }
-    }
-
-    /**
-     * Returns either NOT_LOADING, or LOADED if the onFaviconLoaded call could
-     * be made on the main thread.
-     * If no listener is provided, NOT_LOADING is returned.
-     */
-    static int dispatchResult(final String pageUrl, final String faviconURL, final Bitmap image,
-            final OnFaviconLoadedListener listener) {
-        if (listener == null) {
-            return NOT_LOADING;
-        }
-
-        if (ThreadUtils.isOnUiThread()) {
-            listener.onFaviconLoaded(pageUrl, faviconURL, image);
-            return LOADED;
-        }
-
-        // We want to always run the listener on UI thread.
-        ThreadUtils.postToUiThread(new Runnable() {
-            @Override
-            public void run() {
-                listener.onFaviconLoaded(pageUrl, faviconURL, image);
-            }
-        });
-        return NOT_LOADING;
-    }
-
-    /**
-     * Get a Favicon as close as possible to the target dimensions for the URL provided.
-     * If a result is instantly available from the cache, it is returned and the listener is invoked.
-     * Otherwise, the result is drawn from the database or network and the listener invoked when the
-     * result becomes available.
-     *
-     * @param pageURL Page URL for which a Favicon is desired.
-     * @param faviconURL URL of the Favicon to be downloaded, if known. If none provided, an educated
-     *                    guess is made by the system.
-     * @param targetSize Target size of the returned Favicon
-     * @param listener Listener to call with the result of the load operation, if the result is not
-     *                  immediately available.
-     * @return The id of the asynchronous task created, NOT_LOADING if none is created, or
-     *         LOADED if the value could be dispatched on the current thread.
-     */
-    public static int getSizedFavicon(Context context, String pageURL, String faviconURL,
-                                      LoadType loadType, int targetSize, int flags, OnFaviconLoadedListener listener) {
-        // Do we know the favicon URL for this page already?
-        String cacheURL = faviconURL;
-        if (cacheURL == null) {
-            cacheURL = pageURLMappings.get(pageURL);
-        }
-
-        // If there's no favicon URL given, try and hit the cache with the default one.
-        if (cacheURL == null) {
-            cacheURL = guessDefaultFaviconURL(pageURL);
-        }
-
-        if (cacheURL == null) {
-            // If it's something we can't even figure out a default URL for, just give up.
-            return dispatchResult(pageURL, null, defaultFavicon, listener);
-        } else if (loadType != LoadType.PRIVILEGED &&
-                !(cacheURL.startsWith("http://") || cacheURL.startsWith("https://"))) {
-            // Don't load internal / other favicons for non-privileged pages. This is only relevant
-            // for getSizedFavicon since this is the only method that allows using a specific favicon
-            // URL. All other methods operate via the cache, icons will only end up in the cache
-            // if we load them via getSizedFavicon in the first place.
-            return NOT_LOADING;
-        }
-
-        Bitmap cachedIcon = getSizedFaviconFromCache(cacheURL, targetSize);
-        if (cachedIcon != null) {
-            return dispatchResult(pageURL, cacheURL, cachedIcon, listener);
-        }
-
-        // Check if favicon has failed.
-        if (faviconsCache.isFailedFavicon(cacheURL)) {
-            return dispatchResult(pageURL, cacheURL, defaultFavicon, listener);
-        }
-
-        // Failing that, try and get one from the database or internet.
-        return loadUncachedFavicon(context, pageURL, faviconURL, flags, targetSize, listener);
-    }
-
-    /**
-     * Returns the cached Favicon closest to the target size if any exists or is coercible. Returns
-     * null otherwise. Does not query the database or network for the Favicon is the result is not
-     * immediately available.
-     *
-     * @param faviconURL URL of the Favicon to query for.
-     * @param targetSize The desired size of the returned Favicon.
-     * @return The cached Favicon, rescaled to be as close as possible to the target size, if any exists.
-     *         null if no applicable Favicon exists in the cache.
-     */
-    static Bitmap getSizedFaviconFromCache(String faviconURL, int targetSize) {
-        return faviconsCache.getFaviconForDimensions(faviconURL, targetSize);
-    }
-
-    /**
-     * Attempts to find a Favicon for the provided page URL from either the mem cache or the database.
-     * Does not need an explicit favicon URL, since, as we are accessing the database anyway, we
-     * can query the history DB for the Favicon URL.
-     * Handy for easing the transition from caching with page URLs to caching with Favicon URLs.
-     *
-     * A null result is passed to the listener if no value is locally available. The Favicon is not
-     * added to the failure cache.
-     *
-     * @param pageURL Page URL for which a Favicon is wanted.
-     * @param targetSize Target size of the desired Favicon to pass to the cache query
-     * @param callback Callback to fire with the result.
-     * @return The job ID of the spawned async task, if any.
-     */
-    public static int getSizedFaviconForPageFromLocal(Context context, final String pageURL, final int targetSize,
-                                                      final OnFaviconLoadedListener callback) {
-        // Firstly, try extremely hard to cheat.
-        // Have we cached this favicon URL? If we did, we can consult the memcache right away.
-        final String targetURL = pageURLMappings.get(pageURL);
-        if (targetURL != null) {
-            // Check if favicon has failed.
-            if (faviconsCache.isFailedFavicon(targetURL)) {
-                return dispatchResult(pageURL, targetURL, null, callback);
-            }
-
-            // Do we have a Favicon in the cache for this favicon URL?
-            final Bitmap result = getSizedFaviconFromCache(targetURL, targetSize);
-            if (result != null) {
-                // Victory - immediate response!
-                return dispatchResult(pageURL, targetURL, result, callback);
-            }
-        }
-
-        // No joy using in-memory resources. Go to background thread and ask the database.
-        // Note: this is a near duplicate of loadUncachedFavicon, however loadUncachedFavicon
-        // can download favicons, whereas we want to restrict ourselves to the cache.
-        final LoadFaviconTask task =
-            new LoadFaviconTask(context, pageURL, targetURL, 0, callback, targetSize, /* onlyFromLocal: */ true);
-        final int taskId = task.getId();
-        synchronized (loadTasks) {
-            loadTasks.put(taskId, task);
-        }
-        task.execute();
-
-        return taskId;
-    }
-
-    public static int getSizedFaviconForPageFromLocal(Context context, final String pageURL, final OnFaviconLoadedListener callback) {
-        return getSizedFaviconForPageFromLocal(context, pageURL, defaultFaviconSize, callback);
-    }
-
-    /**
-     * Helper method to determine the URL of the Favicon image for a given page URL by querying the
-     * history database. Should only be called from the background thread - does database access.
-     *
-     * @param db The LocalBrowserDB to use when accessing favicons.
-     * @param cr A ContentResolver to run queries through.
-     * @param pageURL The URL of a webpage with a Favicon.
-     * @return The URL of the Favicon used by that webpage, according to either the History database
-     *         or a somewhat educated guess.
-     */
-    public static String getFaviconURLForPageURL(final BrowserDB db, final ContentResolver cr, final String pageURL) {
-        // Attempt to determine the Favicon URL from the Tabs datastructure. Can dodge having to use
-        // the database sometimes by doing this.
-        String targetURL;
-        Tab theTab = Tabs.getInstance().getFirstTabForUrl(pageURL);
-        if (theTab != null) {
-            targetURL = theTab.getFaviconURL();
-            if (targetURL != null) {
-                return targetURL;
-            }
-        }
-
-        // Try to find the faviconURL in the history and/or bookmarks table.
-        targetURL = db.getFaviconURLFromPageURL(cr, pageURL);
-        if (targetURL != null) {
-            return targetURL;
-        }
-
-        // If we still can't find it, fall back to the default URL and hope for the best.
-        return guessDefaultFaviconURL(pageURL);
-    }
-
-    /**
-     * Helper function to create an async job to load a Favicon which does not exist in the memcache.
-     * Contains logic to prevent the repeated loading of Favicons which have previously failed.
-     * There is no support for recovery from transient failures.
-     *
-     * @param pageURL URL of the page for which to load a Favicon. If null, no job is created.
-     * @param faviconURL The URL of the Favicon to load. If null, an attempt to infer the value from
-     *                   the history database will be made, and ultimately an attempt to guess will
-     *                   be made.
-     * @param flags Flags to be used by the LoadFaviconTask while loading. Currently only one flag
-     *              is supported, LoadFaviconTask.FLAG_PERSIST.
-     *              If FLAG_PERSIST is set and the Favicon is ultimately loaded from the internet,
-     *              the downloaded Favicon is subsequently stored in the local database.
-     *              If FLAG_PERSIST is unset, the downloaded Favicon is stored only in the memcache.
-     *              FLAG_PERSIST has no effect on loads which come from the database.
-     * @param listener The OnFaviconLoadedListener to invoke with the result of this Favicon load.
-     * @return The id of the LoadFaviconTask handling this job.
-     */
-    private static int loadUncachedFavicon(Context context, String pageURL, String faviconURL, int flags,
-                                           int targetSize, OnFaviconLoadedListener listener) {
-        // Handle the case where we have no page url.
-        if (TextUtils.isEmpty(pageURL)) {
-            dispatchResult(null, null, null, listener);
-            return NOT_LOADING;
-        }
-
-        final LoadFaviconTask task =
-            new LoadFaviconTask(context, pageURL, faviconURL, flags, listener, targetSize, false);
-        final int taskId = task.getId();
-        synchronized (loadTasks) {
-            loadTasks.put(taskId, task);
-        }
-        task.execute();
-
-        return taskId;
-    }
-
-    public static void putFaviconInMemCache(String pageUrl, Bitmap image) {
-        faviconsCache.putSingleFavicon(pageUrl, image);
-    }
-
-    /**
-     * Adds the bitmaps given by the specified iterator to the cache associated with the url given.
-     * Future requests for images will be able to select the least larger image than the target
-     * size from this new set of images.
-     *
-     * @param pageUrl The URL to associate the new favicons with.
-     * @param images An iterator over the new favicons to put in the cache.
-     */
-    public static void putFaviconsInMemCache(String pageUrl, Iterator<Bitmap> images, boolean permanently) {
-        faviconsCache.putFavicons(pageUrl, images, permanently);
-    }
-
-    public static void putFaviconsInMemCache(String pageUrl, Iterator<Bitmap> images) {
-        putFaviconsInMemCache(pageUrl, images, false);
-    }
-
-    public static void clearMemCache() {
-        faviconsCache.evictAll();
-        pageURLMappings.evictAll();
-    }
-
-    public static void putFaviconInFailedCache(String faviconURL) {
-        faviconsCache.putFailed(faviconURL);
-    }
-
-    public static boolean cancelFaviconLoad(int taskId) {
-        if (taskId == NOT_LOADING) {
-            return false;
-        }
-
-        synchronized (loadTasks) {
-            if (loadTasks.indexOfKey(taskId) < 0) {
-                return false;
-            }
-
-            Log.v(LOGTAG, "Cancelling favicon load " + taskId + ".");
-            LoadFaviconTask task = loadTasks.get(taskId);
-            return task.cancel();
-        }
-    }
-
-    public static void close() {
-        Log.d(LOGTAG, "Closing Favicons database");
-
-        // Close the Executor to new tasks.
-        longRunningExecutor.shutdown();
-
-        // Cancel any pending tasks
-        synchronized (loadTasks) {
-            final int count = loadTasks.size();
-            for (int i = 0; i < count; i++) {
-                cancelFaviconLoad(loadTasks.keyAt(i));
-            }
-            loadTasks.clear();
-        }
-    }
-
-    /**
-     * Get the dominant colour of the Favicon at the URL given, if any exists in the cache.
-     *
-     * @param url The URL of the Favicon, to be used as the cache key for the colour value.
-     * @return The dominant colour of the provided Favicon.
-     */
-    public static int getFaviconColor(String url) {
-        return faviconsCache.getDominantColor(url);
-    }
-
-    /**
-     * Called by GeckoApp on startup to pass this class a reference to the GeckoApp object used as
-     * the application's Context.
-     * Consider replacing with references to a staticly held reference to the GeckoApp object.
-     *
-     * @param context A reference to the GeckoApp instance.
-     */
-    public static void initializeWithContext(Context context) throws IllegalStateException {
-        // Prevent multiple-initialisation.
-        if (!isInitialized.compareAndSet(false, true)) {
-            return;
-        }
-
-        final Resources res = context.getResources();
-
-        final Drawable defaultFaviconDrawable = res.getDrawable(R.drawable.toolbar_favicon_default);
-        if (defaultFaviconDrawable instanceof BitmapDrawable) {
-            defaultFavicon = ((BitmapDrawable) defaultFaviconDrawable).getBitmap();
-        } else {
-            throw new IllegalStateException("toolbar_favicon_default wasn't a bitmap resource!");
-        }
-
-        defaultFaviconSize = res.getDimensionPixelSize(R.dimen.favicon_bg);
-
-        // Screen-density-adjusted upper limit on favicon size. Favicons larger than this are
-        // downscaled to this size or discarded.
-        largestFaviconSize = res.getDimensionPixelSize(R.dimen.favicon_largest_interesting_size);
-
-        browserToolbarFaviconSize = res.getDimensionPixelSize(R.dimen.browser_toolbar_favicon_size);
-
-        faviconsCache = new FaviconCache(FAVICON_CACHE_SIZE_BYTES, largestFaviconSize);
-
-        // Initialize page mappings for each of our special pages.
-        for (String url : AboutPages.DEFAULT_ICON_PAGES) {
-            pageURLMappings.putWithoutEviction(url, BUILT_IN_FAVICON_URL);
-        }
-
-        // Load and cache the built-in favicon in each of its sizes.
-        // TODO: don't open the zip twice!
-        List<Bitmap> toInsert = Arrays.asList(loadBrandingBitmap(context, "favicon64.png"),
-                                              loadBrandingBitmap(context, "favicon32.png"));
-
-        putFaviconsInMemCache(BUILT_IN_FAVICON_URL, toInsert.iterator(), true);
-
-        pageURLMappings.putWithoutEviction(AboutPages.HOME, BUILT_IN_SEARCH_URL);
-        List<Bitmap> searchIcons = Collections.singletonList(BitmapFactory.decodeResource(res, R.drawable.search_icon_inactive));
-        putFaviconsInMemCache(BUILT_IN_SEARCH_URL, searchIcons.iterator(), true);
-    }
-
-    /**
-     * Compute a string like:
-     * "jar:jar:file:///data/app/org.mozilla.firefox-1.apk!/assets/omni.ja!/chrome/chrome/content/branding/favicon64.png"
-     */
-    private static String getBrandingBitmapPath(Context context, String name) {
-        return GeckoJarReader.getJarURL(context, "chrome/chrome/content/branding/" + name);
-    }
-
-    private static Bitmap loadBrandingBitmap(Context context, String name) {
-        Bitmap b = GeckoJarReader.getBitmap(context,
-                                            context.getResources(),
-                                            getBrandingBitmapPath(context, name));
-        if (b == null) {
-            throw new IllegalStateException("Bitmap " + name + " missing from JAR!");
-        }
-        return b;
-    }
-
-    /**
-     * Helper method to get the default Favicon URL for a given pageURL. Generally: somewhere.com/favicon.ico
-     *
-     * @param pageURL Page URL for which a default Favicon URL is requested
-     * @return The default Favicon URL.
-     */
-    public static String guessDefaultFaviconURL(String pageURL) {
-        // Special-casing for about: pages. The favicon for about:pages which don't provide a link tag
-        // is bundled in the database, keyed only by page URL, hence the need to return the page URL
-        // here. If the database ever migrates to stop being silly in this way, this can plausibly
-        // be removed.
-        if (TextUtils.isEmpty(pageURL)) {
-            return null;
-        }
-        if (AboutPages.isAboutPage(pageURL) || pageURL.startsWith("jar:")) {
-            return pageURL;
-        }
-
-        try {
-            // Fall back to trying "someScheme:someDomain.someExtension/favicon.ico".
-            Uri u = Uri.parse(pageURL);
-            Uri.Builder builder = new Uri.Builder();
-            builder.scheme(u.getScheme())
-                   .authority(u.getAuthority())
-                   .appendPath("favicon.ico");
-            return builder.build().toString();
-        } catch (Exception e) {
-            Log.d(LOGTAG, "Exception getting default favicon URL");
-            return null;
-        }
-    }
-
-    /**
-     * Helper function to determine if we can decode a particular mime type.
-     * @param imgType Mime type to check for decodability.
-     * @return false if the given mime type is certainly not decodable, true if it might be.
-     */
-    public static boolean canDecodeType(String imgType) {
-        return "".equals(imgType) || sDecodableMimeTypes.contains(imgType);
-    }
-
-    /**
-     * Helper function to determine if the provided mime type is that of a format that can contain
-     * multiple image types. At time of writing, the only such type is ICO.
-     * @param mimeType Mime type to check.
-     * @return true if the given mime type is a container type, false otherwise.
-     */
-    public static boolean isContainerType(String mimeType) {
-        return sDecodableMimeTypes.contains(mimeType);
-    }
-
-    public static void removeLoadTask(int taskId) {
-        synchronized (loadTasks) {
-            loadTasks.delete(taskId);
-        }
-    }
-
-    /**
-     * Method to wrap FaviconCache.isFailedFavicon for use by LoadFaviconTask.
-     *
-     * @param faviconURL Favicon URL to check for failure.
-     */
-    static boolean isFailedFavicon(String faviconURL) {
-        return faviconsCache.isFailedFavicon(faviconURL);
-    }
-
-    /**
-     * Sidestep the cache and get, from either the database or the internet, a favicon
-     * suitable for use as an app icon for the provided URL.
-     *
-     * Useful for creating homescreen shortcuts without being limited
-     * by possibly low-resolution values in the cache.
-     *
-     * The icon will be scaled to the preferred Android launcher icon size.
-     *
-     * Deduces the favicon URL from the browser database, guessing if necessary.
-     *
-     * @param url page URL to get a large favicon image for.
-     * @param onFaviconLoadedListener listener to call back with the result.
-     */
-    private static void getPreferredSizeFaviconForPage(Context context, String url, String iconURL, OnFaviconLoadedListener onFaviconLoadedListener) {
-        int preferredSize = GeckoAppShell.getPreferredIconSize();
-        loadUncachedFavicon(context, url, iconURL, LoadFaviconTask.FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS, preferredSize, onFaviconLoadedListener);
-    }
-
-    /**
-     * Load the icon that is the most suitable for using as a home screen shortcut.
-     *
-     * This method will try to load a 'touch icon' first. If not available it will fallback to use
-     * the best available favicon.
-     *
-     * This implementation sidesteps the cache and will load the icon from the database or the
-     * internet. See getPreferredSizeFaviconForPage().
-     */
-    public static void getPreferredIconForHomeScreenShortcut(Context context, String url, OnFaviconLoadedListener onFaviconLoadedListener) {
-        ThreadUtils.assertOnBackgroundThread();
-
-        final BrowserDB db = GeckoProfile.get(context).getDB();
-
-        final String metadataQueryURL = StringUtils.stripRef(url);
-
-        final ContentResolver cr = context.getContentResolver();
-        final Map<String, Map<String, Object>> metadata = db.getURLMetadata().getForURLs(cr,
-                Collections.singletonList(metadataQueryURL),
-                Collections.singletonList(URLMetadataTable.TOUCH_ICON_COLUMN)
-        );
-
-        final Map<String, Object> row = metadata.get(metadataQueryURL);
-
-        String touchIconURL = null;
-
-        if (row != null) {
-            touchIconURL = (String) row.get(URLMetadataTable.TOUCH_ICON_COLUMN);
-        }
-
-        if (touchIconURL != null &&
-            !(touchIconURL.startsWith("http://") || touchIconURL.startsWith("https://"))) {
-            // We definitely don't want to load internal icons for homescreen shortcuts. See
-            // our use of LoadType.PRIVILEGED above for where allow non http(s) icons
-            touchIconURL = null;
-        }
-
-        // Retrieve the icon while bypassing the cache. Homescreen icon creation is a one-off event, hence it isn't
-        // useful to cache these icons. (Android takes care of storing homescreen icons after a shortcut
-        // has been created.)
-        // The cache is also (currently) limited to 32dp, hence we explicitly need to avoid accessing those icons.
-        // If touchIconURL is null, then Favicons falls back to finding the best possible favicon for
-        // the site URI, hence we can use this call even when there is no touchIcon defined.
-        getPreferredSizeFaviconForPage(context, url, touchIconURL, onFaviconLoadedListener);
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/LoadFaviconTask.java
+++ /dev/null
@@ -1,687 +0,0 @@
-/* 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.favicons;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.util.Log;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.distribution.PartnerBookmarksProviderProxy;
-import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
-import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
-import org.mozilla.gecko.util.GeckoJarReader;
-import org.mozilla.gecko.util.IOUtils;
-import org.mozilla.gecko.util.ProxySelector;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static org.mozilla.gecko.util.IOUtils.ConsumedInputStream;
-
-/**
- * Class representing the asynchronous task to load a Favicon which is not currently in the in-memory
- * cache.
- * The implementation initially tries to get the Favicon from the database. Upon failure, the icon
- * is loaded from the internet.
- */
-public class LoadFaviconTask {
-    private static final String LOGTAG = "LoadFaviconTask";
-
-    // Access to this map needs to be synchronized prevent multiple jobs loading the same favicon
-    // from executing concurrently.
-    private static final HashMap<String, LoadFaviconTask> loadsInFlight = new HashMap<>();
-
-    public static final int FLAG_PERSIST = 1;
-    /**
-     * Bypass all caches - this is used to directly retrieve the requested icon. Without this flag,
-     * favicons will first be pushed into the memory cache (and possibly permanent cache if using FLAG_PERSIST),
-     * where they will be downscaled to the maximum cache size, before being retrieved from the cache (resulting
-     * in a possibly smaller icon size).
-     */
-    public static final int FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS = 2;
-
-    /**
-     * If downloading from the favicon URL failed then do NOT try to guess the default URL and
-     * download from the default URL.
-     */
-    public static final int FLAG_NO_DOWNLOAD_FROM_GUESSED_DEFAULT_URL = 4;
-
-    private static final int MAX_REDIRECTS_TO_FOLLOW = 5;
-    // The default size of the buffer to use for downloading Favicons in the event no size is given
-    // by the server.
-    public static final int DEFAULT_FAVICON_BUFFER_SIZE = 25000;
-
-    private static final AtomicInteger nextFaviconLoadId = new AtomicInteger(0);
-    private final Context context;
-    private final int id;
-    private final String pageUrl;
-    private String faviconURL;
-    private final OnFaviconLoadedListener listener;
-    private final int flags;
-    private final BrowserDB db;
-
-    private final boolean onlyFromLocal;
-    volatile boolean mCancelled;
-
-    // Assuming square favicons, judging by width only is acceptable.
-    protected int targetWidthAndHeight;
-    private LinkedList<LoadFaviconTask> chainees;
-    private boolean isChaining;
-
-    private static class Response {
-        public final int contentLength;
-        public final InputStream stream;
-
-        private Response(InputStream stream, int contentLength) {
-            this.stream = stream;
-            this.contentLength = contentLength;
-        }
-    }
-
-    public LoadFaviconTask(Context context, String pageURL, String faviconURL, int flags, OnFaviconLoadedListener listener,
-                           int targetWidth, boolean onlyFromLocal) {
-        id = nextFaviconLoadId.incrementAndGet();
-
-        this.context = context;
-        db = GeckoProfile.get(context).getDB();
-        this.pageUrl = pageURL;
-        this.faviconURL = faviconURL;
-        this.listener = listener;
-        this.flags = flags;
-        this.targetWidthAndHeight = targetWidth;
-        this.onlyFromLocal = onlyFromLocal;
-    }
-
-    // Runs in background thread
-    private LoadFaviconResult loadFaviconFromDb(final BrowserDB db) {
-        ContentResolver resolver = context.getContentResolver();
-        return db.getFaviconForUrl(resolver, faviconURL);
-    }
-
-    // Runs in background thread
-    private void saveFaviconToDb(final BrowserDB db, final byte[] encodedFavicon) {
-        if (encodedFavicon == null) {
-            return;
-        }
-
-        if ((flags & FLAG_PERSIST) == 0) {
-            return;
-        }
-
-        ContentResolver resolver = context.getContentResolver();
-        db.updateFaviconForUrl(resolver, pageUrl, encodedFavicon, faviconURL);
-    }
-
-    /**
-     * Helper method for trying the download request to grab a Favicon.
-     * @param faviconURI URL of Favicon to try and download
-     * @return The HttpResponse containing the downloaded Favicon if successful, null otherwise.
-     */
-    private Response tryDownload(URI faviconURI) throws URISyntaxException, IOException {
-        HashSet<String> visitedLinkSet = new HashSet<>();
-        visitedLinkSet.add(faviconURI.toString());
-        return tryDownloadRecurse(faviconURI, visitedLinkSet);
-    }
-    private Response tryDownloadRecurse(URI faviconURI, HashSet<String> visited) throws URISyntaxException, IOException {
-        if (visited.size() == MAX_REDIRECTS_TO_FOLLOW) {
-            return null;
-        }
-
-        HttpURLConnection connection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(faviconURI);
-        connection.setRequestProperty("User-Agent", GeckoAppShell.getGeckoInterface().getDefaultUAString());
-
-        connection.connect();
-
-        // Was the response a failure?
-        int status = connection.getResponseCode();
-
-        // Handle HTTP status codes requesting a redirect.
-        if (status >= 300 && status < 400) {
-            final String newURI = connection.getHeaderField("Location");
-
-            // Handle mad webservers.
-            try {
-                if (newURI == null || newURI.equals(faviconURI.toString())) {
-                    return null;
-                }
-
-                if (visited.contains(newURI)) {
-                    // Already been redirected here - abort.
-                    return null;
-                }
-
-                visited.add(newURI);
-            } finally {
-                connection.disconnect();
-            }
-
-            return tryDownloadRecurse(new URI(newURI), visited);
-        }
-
-        if (status >= 400) {
-            connection.disconnect();
-            return null;
-        }
-
-        return new Response(connection.getInputStream(), connection.getHeaderFieldInt("Content-Length", -1));
-    }
-
-    /**
-     * Retrieve the specified favicon from the JAR, returning null if it's not
-     * a JAR URI.
-     */
-    private Bitmap fetchJARFavicon(String uri) {
-        if (uri == null) {
-            return null;
-        }
-        if (uri.startsWith("jar:jar:")) {
-            Log.d(LOGTAG, "Fetching favicon from JAR.");
-            try {
-                return GeckoJarReader.getBitmap(context, context.getResources(), uri);
-            } catch (Exception e) {
-                // Just about anything could happen here.
-                Log.w(LOGTAG, "Error fetching favicon from JAR.", e);
-                return null;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Fetch icon from a content provider following the partner bookmarks provider contract.
-     */
-    private Bitmap fetchContentProviderFavicon(String uri, int targetWidthAndHeight) {
-        if (TextUtils.isEmpty(uri)) {
-            return null;
-        }
-
-        if (!uri.startsWith("content://")) {
-            return null;
-        }
-
-        Cursor cursor = context.getContentResolver().query(
-                Uri.parse(uri),
-                new String[] {
-                        PartnerBookmarksProviderProxy.PartnerContract.TOUCHICON,
-                        PartnerBookmarksProviderProxy.PartnerContract.FAVICON,
-                },
-                null,
-                null,
-                null
-        );
-
-        if (cursor == null) {
-            return null;
-        }
-
-        try {
-            if (!cursor.moveToFirst()) {
-                return null;
-            }
-
-            Bitmap icon = decodeFromCursor(cursor, PartnerBookmarksProviderProxy.PartnerContract.TOUCHICON, targetWidthAndHeight);
-            if (icon != null) {
-                return icon;
-            }
-
-            icon = decodeFromCursor(cursor, PartnerBookmarksProviderProxy.PartnerContract.FAVICON, targetWidthAndHeight);
-            if (icon != null) {
-                return icon;
-            }
-        } finally {
-            cursor.close();
-        }
-
-        return null;
-    }
-
-    private Bitmap decodeFromCursor(Cursor cursor, String column, int targetWidthAndHeight) {
-        final int index = cursor.getColumnIndex(column);
-        if (index == -1) {
-            return null;
-        }
-
-        if (cursor.isNull(index)) {
-            return null;
-        }
-
-        final byte[] data = cursor.getBlob(index);
-        LoadFaviconResult result = FaviconDecoder.decodeFavicon(data, 0, data.length);
-        if (result == null) {
-            return null;
-        }
-
-        return result.getBestBitmap(targetWidthAndHeight);
-    }
-
-    // Runs in background thread.
-    // Does not attempt to fetch from JARs.
-    private LoadFaviconResult downloadFavicon(URI targetFaviconURI) {
-        if (targetFaviconURI == null) {
-            return null;
-        }
-
-        // Only get favicons for HTTP/HTTPS.
-        String scheme = targetFaviconURI.getScheme();
-        if (!"http".equals(scheme) && !"https".equals(scheme)) {
-            return null;
-        }
-
-        LoadFaviconResult result = null;
-
-        try {
-            result = downloadAndDecodeImage(targetFaviconURI);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error reading favicon", e);
-        } catch (OutOfMemoryError e) {
-            Log.e(LOGTAG, "Insufficient memory to process favicon");
-        }
-
-        return result;
-    }
-
-    /**
-     * Download the Favicon from the given URL and pass it to the decoder function.
-     *
-     * @param targetFaviconURL URL of the favicon to download.
-     * @return A LoadFaviconResult containing the bitmap(s) extracted from the downloaded file, or
-     *         null if no or corrupt data ware received.
-     * @throws IOException If attempts to fully read the stream result in such an exception, such as
-     *                     in the event of a transient connection failure.
-     * @throws URISyntaxException If the underlying call to tryDownload retries and raises such an
-     *                            exception trying a fallback URL.
-     */
-    private LoadFaviconResult downloadAndDecodeImage(URI targetFaviconURL) throws IOException, URISyntaxException {
-        // Try the URL we were given.
-        Response response = tryDownload(targetFaviconURL);
-        if (response == null) {
-            return null;
-        }
-
-        // Decode the image from the fetched response.
-        try {
-            return decodeImageFromResponse(response);
-        } finally {
-            // Close the stream and free related resources.
-            IOUtils.safeStreamClose(response.stream);
-        }
-    }
-
-    /**
-     * Copies the favicon stream to a buffer and decodes downloaded content  into bitmaps using the
-     * FaviconDecoder.
-     *
-     * @param response Response containing the favicon stream to decode.
-     * @return A LoadFaviconResult containing the bitmap(s) extracted from the downloaded file, or
-     *         null if no or corrupt data were received.
-     * @throws IOException If attempts to fully read the stream result in such an exception, such as
-     *                     in the event of a transient connection failure.
-     */
-    private LoadFaviconResult decodeImageFromResponse(Response response) throws IOException {
-        // This may not be provided, but if it is, it's useful.
-        int bufferSize;
-        if (response.contentLength > 0) {
-            // The size was reported and sane, so let's use that.
-            // Integer overflow should not be a problem for Favicon sizes...
-            bufferSize = response.contentLength + 1;
-        } else {
-            // No declared size, so guess and reallocate later if it turns out to be too small.
-            bufferSize = DEFAULT_FAVICON_BUFFER_SIZE;
-        }
-
-        // Read the InputStream into a byte[].
-        ConsumedInputStream result = IOUtils.readFully(response.stream, bufferSize);
-        if (result == null) {
-            return null;
-        }
-
-        // Having downloaded the image, decode it.
-        return FaviconDecoder.decodeFavicon(result.getData(), 0, result.consumedLength);
-    }
-
-    // LoadFaviconTasks are performed on a unique background executor thread
-    // to avoid network blocking.
-    public final void execute() {
-        try {
-            Favicons.longRunningExecutor.execute(new Runnable() {
-                @Override
-                public void run() {
-                    final Bitmap result = doInBackground(db);
-
-                    ThreadUtils.getUiHandler().post(new Runnable() {
-                       @Override
-                        public void run() {
-                            if (mCancelled) {
-                                onCancelled();
-                            } else {
-                                onPostExecute(result);
-                            }
-                        }
-                    });
-                }
-            });
-          } catch (RejectedExecutionException e) {
-              // If our executor is unavailable.
-              onCancelled();
-          }
-    }
-
-    public final boolean cancel() {
-        mCancelled = true;
-        return true;
-    }
-
-    public final boolean isCancelled() {
-        return mCancelled;
-    }
-
-    Bitmap doInBackground(final BrowserDB db) {
-        if (isCancelled()) {
-            return null;
-        }
-
-        // Attempt to decode the favicon URL as a data URL. We don't bother storing such URIs in
-        // the database: the cost of decoding them here probably doesn't exceed the cost of mucking
-        // about with the DB.
-        final boolean isEmpty = TextUtils.isEmpty(faviconURL);
-        if (!isEmpty) {
-            LoadFaviconResult uriBitmaps = FaviconDecoder.decodeDataURI(faviconURL);
-            if (uriBitmaps != null) {
-                return pushToCacheAndGetResult(uriBitmaps);
-            }
-        }
-
-        String storedFaviconUrl;
-        boolean isUsingDefaultURL = false;
-
-        // Handle the case of malformed favicon URL.
-        // If favicon is empty, fall back to the stored one.
-        if (isEmpty) {
-            // Try to get the favicon URL from the memory cache.
-            final ContentResolver cr = context.getContentResolver();
-            storedFaviconUrl = Favicons.getFaviconURLForPageURLFromCache(pageUrl);
-
-            // If that failed, try to get the URL from the database.
-            if (storedFaviconUrl == null) {
-                storedFaviconUrl = Favicons.getFaviconURLForPageURL(db, cr, pageUrl);
-                if (storedFaviconUrl != null) {
-                    // If that succeeded, cache the URL loaded from the database in memory.
-                    Favicons.putFaviconURLForPageURLInCache(pageUrl, storedFaviconUrl);
-                }
-            }
-
-            // If we found a faviconURL - use it.
-            if (storedFaviconUrl != null) {
-                faviconURL = storedFaviconUrl;
-            } else {
-                // If we don't have a stored one, fall back to the default.
-                faviconURL = Favicons.guessDefaultFaviconURL(pageUrl);
-
-                if (TextUtils.isEmpty(faviconURL)) {
-                    return null;
-                }
-                isUsingDefaultURL = true;
-            }
-        }
-
-        // Check if favicon has failed - if so, give up. We need this check because, sometimes, we
-        // didn't know the real Favicon URL until we asked the database.
-        if (Favicons.isFailedFavicon(faviconURL)) {
-            return null;
-        }
-
-        if (isCancelled()) {
-            return null;
-        }
-
-        Bitmap image;
-        // Determine if there is already an ongoing task to fetch the Favicon we desire.
-        // If there is, just join the queue and wait for it to finish. If not, we carry on.
-        synchronized (loadsInFlight) {
-            // Another load of the current Favicon is already underway
-            LoadFaviconTask existingTask = loadsInFlight.get(faviconURL);
-            if (existingTask != null && !existingTask.isCancelled()) {
-                existingTask.chainTasks(this);
-                isChaining = true;
-
-                // If we are chaining, we want to keep the first task started to do this job as the one
-                // in the hashmap so subsequent tasks will add themselves to its chaining list.
-                return null;
-            }
-
-            // We do not want to update the hashmap if the task has chained - other tasks need to
-            // chain onto the same parent task.
-            loadsInFlight.put(faviconURL, this);
-        }
-
-        if (isCancelled()) {
-            return null;
-        }
-
-        LoadFaviconResult loadedBitmaps = null;
-        // If there are no valid bitmaps decoded, the returned LoadFaviconResult is null.
-        if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) == 0) {
-            loadedBitmaps = loadFaviconFromDb(db);
-            if (loadedBitmaps != null) {
-                return pushToCacheAndGetResult(loadedBitmaps);
-            }
-        }
-
-        if (onlyFromLocal || isCancelled()) {
-            return null;
-        }
-
-        // Let's see if it's in a JAR.
-        image = fetchJARFavicon(faviconURL);
-        if (imageIsValid(image)) {
-            // We don't want to put this into the DB.
-            Favicons.putFaviconInMemCache(faviconURL, image);
-            return image;
-        }
-
-        // Download from a content provider
-        image = fetchContentProviderFavicon(faviconURL, targetWidthAndHeight);
-        if (imageIsValid(image)) {
-            // We don't want to put this into the DB.
-            Favicons.putFaviconInMemCache(faviconURL, image);
-            return image;
-        }
-
-        try {
-            loadedBitmaps = downloadFavicon(new URI(faviconURL));
-        } catch (URISyntaxException e) {
-            Log.e(LOGTAG, "The provided favicon URL is not valid");
-            return null;
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Couldn't download favicon.", e);
-        }
-
-        if (loadedBitmaps != null) {
-            if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) == 0) {
-                // Fetching bytes to store can fail. saveFaviconToDb will
-                // do the right thing, but we still choose to cache the
-                // downloaded icon in memory.
-                saveFaviconToDb(db, loadedBitmaps.getBytesForDatabaseStorage());
-                return pushToCacheAndGetResult(loadedBitmaps);
-            } else {
-                return loadedBitmaps.getBestBitmap(targetWidthAndHeight);
-            }
-        }
-
-        if ((FLAG_NO_DOWNLOAD_FROM_GUESSED_DEFAULT_URL & flags) == FLAG_NO_DOWNLOAD_FROM_GUESSED_DEFAULT_URL) {
-            return null;
-        }
-
-        if (isUsingDefaultURL) {
-            Favicons.putFaviconInFailedCache(faviconURL);
-            return null;
-        }
-
-        if (isCancelled()) {
-            return null;
-        }
-
-        // If we're not already trying the default URL, try it now.
-        final String guessed = Favicons.guessDefaultFaviconURL(pageUrl);
-        if (guessed == null) {
-            Favicons.putFaviconInFailedCache(faviconURL);
-            return null;
-        }
-
-        image = fetchJARFavicon(guessed);
-        if (imageIsValid(image)) {
-            // We don't want to put this into the DB.
-            Favicons.putFaviconInMemCache(faviconURL, image);
-            return image;
-        }
-
-        try {
-            loadedBitmaps = downloadFavicon(new URI(guessed));
-        } catch (Exception e) {
-            // Not interesting. It was an educated guess, anyway.
-            return null;
-        }
-
-        if (loadedBitmaps != null) {
-            saveFaviconToDb(db, loadedBitmaps.getBytesForDatabaseStorage());
-            return pushToCacheAndGetResult(loadedBitmaps);
-        }
-
-        return null;
-    }
-
-    /**
-     * Helper method to put the result of a favicon load into the memory cache and then query the
-     * cache for the particular bitmap we want for this request.
-     * This call is certain to succeed, provided there was enough memory to decode this favicon.
-     *
-     * @param loadedBitmaps LoadFaviconResult to store.
-     * @return The optimal favicon available to satisfy this LoadFaviconTask's request, or null if
-     *         we are under extreme memory pressure and find ourselves dropping the cache immediately.
-     */
-    private Bitmap pushToCacheAndGetResult(LoadFaviconResult loadedBitmaps) {
-        Favicons.putFaviconsInMemCache(faviconURL, loadedBitmaps.getBitmaps());
-        return Favicons.getSizedFaviconFromCache(faviconURL, targetWidthAndHeight);
-    }
-
-    private static boolean imageIsValid(final Bitmap image) {
-        return image != null &&
-               image.getWidth() > 0 &&
-               image.getHeight() > 0;
-    }
-
-    void onPostExecute(Bitmap image) {
-        if (isChaining) {
-            return;
-        }
-
-        // Process the result, scale for the listener, etc.
-        processResult(image);
-
-        synchronized (loadsInFlight) {
-            // Prevent any other tasks from chaining on this one.
-            loadsInFlight.remove(faviconURL);
-        }
-
-        // Since any update to chainees is done while holding the loadsInFlight lock, once we reach
-        // this point no further updates to that list can possibly take place (As far as other tasks
-        // are concerned, there is no longer a task to chain from. The above block will have waited
-        // for any tasks that were adding themselves to the list before reaching this point.)
-
-        // As such, I believe we're safe to do the following without holding the lock.
-        // This is nice - we do not want to take the lock unless we have to anyway, and chaining rarely
-        // actually happens outside of the strange situations unit tests create.
-
-        // Share the result with all chained tasks.
-        if (chainees != null) {
-            for (LoadFaviconTask t : chainees) {
-                // In the case that we just decoded multiple favicons, either we're passing the right
-                // image now, or the call into the cache in processResult will fetch the right one.
-                t.processResult(image);
-            }
-        }
-    }
-
-    private void processResult(Bitmap image) {
-        Favicons.removeLoadTask(id);
-        final Bitmap scaled;
-
-        // Notify listeners, scaling if required.
-        if (targetWidthAndHeight != -1 && image != null && image.getWidth() != targetWidthAndHeight) {
-            if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) != 0) {
-                scaled = Bitmap.createScaledBitmap(image, targetWidthAndHeight, targetWidthAndHeight, true);
-            } else {
-                scaled = Favicons.getSizedFaviconFromCache(faviconURL, targetWidthAndHeight);
-            }
-        } else {
-            scaled = image;
-        }
-
-        Favicons.dispatchResult(pageUrl, faviconURL, scaled, listener);
-    }
-
-    void onCancelled() {
-        Favicons.removeLoadTask(id);
-
-        synchronized (loadsInFlight) {
-            // Only remove from the hashmap if the task there is the one that's being canceled.
-            // Cancellation of a task that would have chained is not interesting to the hashmap.
-            final LoadFaviconTask primary = loadsInFlight.get(faviconURL);
-            if (primary == this) {
-                loadsInFlight.remove(faviconURL);
-                return;
-            }
-            if (primary == null) {
-                // This shouldn't happen.
-                return;
-            }
-            if (primary.chainees != null) {
-              primary.chainees.remove(this);
-            }
-        }
-
-        // Note that we don't call the listener callback if the
-        // favicon load is cancelled.
-    }
-
-    /**
-     * When the result of this job is ready, also notify the chainee of the result.
-     * Used for aggregating concurrent requests for the same Favicon into a single actual request.
-     * (Don't want to download a hundred instances of Google's Favicon at once, for example).
-     * The loadsInFlight lock must be held when calling this function.
-     *
-     * @param aChainee LoadFaviconTask
-     */
-    private void chainTasks(LoadFaviconTask aChainee) {
-        if (chainees == null) {
-            chainees = new LinkedList<>();
-        }
-
-        chainees.add(aChainee);
-    }
-
-    int getId() {
-        return id;
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/OnFaviconLoadedListener.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/* 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.favicons;
-
-import android.graphics.Bitmap;
-
-/**
- * Interface to be implemented by objects wishing to listen for favicon load completion events.
- */
-public interface OnFaviconLoadedListener {
-    /**
-     * Called when favicon loading is complete. This will be run on the UI thread.
-     */
-    void onFaviconLoaded(String url, String faviconURL, Bitmap favicon);
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/RemoteFavicon.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/* 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.favicons;
-
-/**
- * Class to represent a Favicon declared on a webpage which we may or may not have downloaded.
- * Tab objects maintain a list of these and attempt to load them in descending order of quality
- * until one works. This enables us to fallback if something fails trying to decode a Favicon.
- */
-public class RemoteFavicon implements Comparable<RemoteFavicon> {
-    public static final int FAVICON_SIZE_ANY = -1;
-
-    // URL of the Favicon referred to by this object.
-    public String faviconUrl;
-
-    // The size of the Favicon, as given in the <link> tag, if any. Zero if unspecified. -1 if "any".
-    public int declaredSize;
-
-    // Mime type of the Favicon, as given in the link tag.
-    public String mimeType;
-
-    public RemoteFavicon(String faviconURL, int givenSize, String mime) {
-        faviconUrl = faviconURL;
-        declaredSize = givenSize;
-        mimeType = mime;
-    }
-
-    /**
-     * Determine equality of two RemoteFavicons.
-     * Two RemoteFavicons are considered equal if they have the same URL, size, and mime type.
-     * @param o The object to compare to this one.
-     * @return true if o is of type RemoteFavicon and is considered equal to this one, false otherwise.
-     */
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof RemoteFavicon)) {
-            return false;
-        }
-        RemoteFavicon oCast = (RemoteFavicon) o;
-
-        return oCast.faviconUrl.equals(faviconUrl) &&
-               oCast.declaredSize == declaredSize &&
-               oCast.mimeType.equals(mimeType);
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode();
-    }
-
-    /**
-     * Establish ordering on Favicons. Lower value in the partial ordering is a "better" Favicon.
-     * @param obj Object to compare against.
-     * @return -1 if this Favicon is "better" than the other, zero if they are equivalent in quality,
-     *         based on the information here, 1 if the other appears "better" than this one.
-     */
-    @Override
-    public int compareTo(RemoteFavicon obj) {
-        // Size "any" trumps everything else.
-        if (declaredSize == FAVICON_SIZE_ANY) {
-            if (obj.declaredSize == FAVICON_SIZE_ANY) {
-                return 0;
-            }
-
-            return -1;
-        }
-
-        if (obj.declaredSize == FAVICON_SIZE_ANY) {
-            return 1;
-        }
-
-        // Unspecified sizes are "worse".
-        if (declaredSize > obj.declaredSize) {
-            return -1;
-        }
-
-        if (declaredSize == obj.declaredSize) {
-            // If there's no other way to choose, we prefer container types. They *might* contain
-            // an image larger than the size given in the <link> tag.
-            if (Favicons.isContainerType(mimeType)) {
-                return -1;
-            }
-            return 0;
-        }
-        return 1;
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/cache/FaviconCache.java
+++ /dev/null
@@ -1,606 +0,0 @@
-/* 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.favicons.cache;
-
-import android.graphics.Bitmap;
-import android.util.Log;
-import org.mozilla.gecko.favicons.Favicons;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Implements a Least-Recently-Used cache for Favicons, keyed by Favicon URL.
- *
- * When a favicon at a particular URL is decoded, it will yield one or more bitmaps.
- * While in memory, these bitmaps are stored in a list, sorted in ascending order of size, in a
- * FaviconsForURL object.
- * The collection of FaviconsForURL objects currently in the cache is stored in backingMap, keyed
- * by favicon URL.
- *
- * A second map exists for permanent cache entries -- ones that are never expired. These entries
- * are assumed to be disjoint from those in the normal cache, and this map is checked first.
- *
- * FaviconsForURL provides a method for obtaining the smallest icon larger than a given size - the
- * most appropriate icon for a particular size.
- * It also distinguishes between "primary" favicons (Ones that have merely been extracted from a
- * file downloaded from the website) and "secondary" favicons (Ones that have been computed locally
- * as resized versions of primary favicons.).
- *
- * FaviconsForURL is also responsible for storing URL-specific, as opposed to favicon-specific,
- * information. For the purposes of this cache, the simplifying assumption that the dominant colour
- * for all favicons served from a particular favicon URL shall be the same is made. (To violate this
- * would mandate serving an ICO or similar file with multiple radically different images in it - an
- * ill-advised and extremely uncommon use-case, for sure.)
- * The dominant colour information is updated as the element is being added to the cache - typically
- * on the background thread.
- * Also present here are the download timestamp and isFailed flag. Upon failure, the flag is set.
- * A constant exists in this file to specify the maximum time permitted between failures before
- * a retry is again permitted.
- *
- * TODO: Expiry of Favicons from the favicon database cache is not implemented. (Bug 914296)
- *
- * A typical request to the cache will consist of a Favicon URL and a target size. The FaviconsForURL
- * object for that URL will be obtained, queried for a favicon matching exactly the needed size, and
- * if successful, the result is returned.
- * If unsuccessful, the object is asked to return the smallest available primary favicon larger than
- * the target size. If this step works, the result is downscaled to create a new secondary favicon,
- * which is then stored (So subsequent requests will succeed at the first step) and returned.
- * If that step fails, the object finally walks backwards through its sequence of favicons until it
- * finds the largest primary favicon smaller than the target. This is then upscaled by a maximum of
- * 2x towards the target size, and the result cached and returned as above.
- *
- * The bitmaps themselves are encapsulated inside FaviconCacheElement objects. These objects contain,
- * as well as the bitmap, a pointer to the encapsulating FaviconsForURL object (Used by the LRU
- * culler), the size of the encapsulated image, a flag indicating if this is a primary favicon, and
- * a flag indicating if the entry is invalid.
- * All FaviconCacheElement objects are tracked in the ordering LinkedList. This is used to record
- * LRU information about FaviconCacheElements. In particular, the most recently used FaviconCacheElement
- * will be at the start of the list, the least recently used at the end of the list.
- *
- * When the cache runs out of space, it removes FaviconCacheElements starting from the end of the list
- * until a sufficient amount of space has been freed.
- * When a secondary favicon is removed in this way, it is simply deleted from its parent FaviconsForURLs
- * object's list of available favicons.
- * The backpointer field on the FaviconCacheElement is used to remove the element from the encapsulating
- * FaviconsForURL object, when this is required.
- * When a primary favicon is removed, its invalid flag is set to true and its bitmap payload is set
- * to null (So it is available for freeing by the garbage collector). This reduces the memory footprint
- * of the icon to essentially zero, but keeps track of which primary favicons exist for this favicon
- * URL.
- * If a subsequent request comes in for that favicon URL, it is then known that a primary of those
- * dimensions is available, just that it is not in the cache. The system is then able to load the
- * primary back into the cache from the database (Where the entirety of the initially encapsulating
- * container-formatted image file is stored).
- * If this were not done, then when processing requests after the culling of primary favicons it would
- * be impossible to distinguish between the nonexistence of a primary and the nonexistence of a primary
- * in the cache without querying the database.
- *
- * The implementation is safe to use from multiple threads and, while is it not entirely strongly
- * consistent all of the time, you almost certainly don't care.
- * The thread-safety implementation used is approximately MRSW with semaphores. An extra semaphore
- * is used to grant mutual exclusion over reordering operations from reader threads (Who thus gain
- * a quasi-writer status to do such limited mutation as is necessary).
- *
- * Reads which race with writes are liable to not see the ongoing write. The cache may return a
- * stale or now-removed value to the caller. Returned values are never invalid, even in the face
- * of concurrent reading and culling.
- */
-public class FaviconCache {
-    private static final String LOGTAG = "FaviconCache";
-
-    // The number of spaces to allocate for favicons in each node.
-    private static final int NUM_FAVICON_SIZES = 4;
-
-    // Dimensions of the largest favicon to store in the cache. Everything is downscaled to this.
-    public final int maxCachedWidth;
-
-    // Retry failed favicons after four hours.
-    public static final long FAILURE_RETRY_MILLISECONDS = 1000 * 60 * 60 * 4;
-
-    // Map relating Favicon URLs with objects representing decoded favicons.
-    // Since favicons may be container formats holding multiple icons, the underlying type holds a
-    // sorted list of bitmap payloads in ascending order of size. The underlying type may be queried
-    // for the least larger payload currently present.
-    private final HashMap<String, FaviconsForURL> backingMap = new HashMap<String, FaviconsForURL>();
-
-    // And the same, but never evicted.
-    private final HashMap<String, FaviconsForURL> permanentBackingMap = new HashMap<String, FaviconsForURL>();
-
-    // A linked list used to implement a queue, defining the LRU properties of the cache. Elements
-    // contained within the various FaviconsForURL objects are held here, the least recently used
-    // of which at the end of the list. When space needs to be reclaimed, the appropriate bitmap is
-    // culled.
-    private final LinkedList<FaviconCacheElement> ordering = new LinkedList<FaviconCacheElement>();
-
-    // The above structures, if used correctly, enable this cache to exhibit LRU semantics across all
-    // favicon payloads in the system, as well as enabling the dynamic selection from the cache of
-    // the primary bitmap most suited to the requested size (in cases where multiple primary bitmaps
-    // are provided by the underlying file format).
-
-    // Current size, in bytes, of the bitmap data present in the LRU cache.
-    private final AtomicInteger currentSize = new AtomicInteger(0);
-
-    // The maximum quantity, in bytes, of bitmap data which may be stored in the cache.
-    private final int maxSizeBytes;
-
-    // This object is used to guard modification to the ordering map. This allows for read transactions
-    // to update the most-recently-used value without needing to take out the write lock.
-    private final Object reorderingLock = new Object();
-
-    // This Reader/Writer lock is to ensure synchronization of reads/writes on both permanent
-    // and non-permanent backing maps. It's created unfair for greater performance.
-    private final ReentrantReadWriteLock backingMapsLock = new ReentrantReadWriteLock(false);
-
-    /**
-     * Called by transactions performing only reads as they start.
-     */
-    private void startRead() {
-        backingMapsLock.readLock().lock();
-    }
-
-    /**
-     * Called by transactions performing only reads as they finish.
-     */
-    private void finishRead() {
-        backingMapsLock.readLock().unlock();
-    }
-
-    /**
-     * Called by writer transactions upon start.
-     */
-    private void startWrite() {
-        backingMapsLock.writeLock().lock();
-    }
-
-    /**
-     * Called by a concluding write transaction - unlocks the structure.
-     */
-    private void finishWrite() {
-        backingMapsLock.writeLock().unlock();
-    }
-
-    public FaviconCache(int maxSize, int maxWidthToCache) {
-        maxSizeBytes = maxSize;
-        maxCachedWidth = maxWidthToCache;
-    }
-
-    /**
-     * Determine if the provided favicon URL is marked as a failure (Has failed to load before -
-     * such icons get blacklisted for a time to prevent us endlessly retrying.)
-     *
-     * @param faviconURL Favicon URL to check if failed in memcache.
-     * @return true if this favicon is blacklisted, false otherwise.
-     */
-    public boolean isFailedFavicon(String faviconURL) {
-        if (faviconURL == null) {
-            return true;
-        }
-
-        startRead();
-
-        try {
-            // If we don't have it in the cache, it certainly isn't a known failure.
-            // Non-evictable favicons are never failed, so we don't need to
-            // check permanentBackingMap.
-            if (!backingMap.containsKey(faviconURL)) {
-                return false;
-            }
-
-            FaviconsForURL container = backingMap.get(faviconURL);
-
-            // If the has failed flag is not set, it's certainly not a known failure.
-            if (!container.hasFailed) {
-                return false;
-            }
-
-            final long failureTimestamp = container.downloadTimestamp;
-
-            // Calculate elapsed time since the failing download.
-            final long failureDiff = System.currentTimeMillis() - failureTimestamp;
-
-            // If the expiry is still in effect, return. Otherwise, continue and unmark the failure.
-            if (failureDiff < FAILURE_RETRY_MILLISECONDS) {
-                return true;
-            }
-        } catch (Exception unhandled) {
-            Log.e(LOGTAG, "FaviconCache exception!", unhandled);
-            return true;
-        }  finally {
-            finishRead();
-        }
-
-        startWrite();
-
-        // If the entry is no longer failed, remove the record of it from the cache.
-        try {
-            recordRemoved(backingMap.remove(faviconURL));
-            return false;
-        } finally {
-            finishWrite();
-        }
-    }
-
-    /**
-     * Mark the indicated page URL as a failed Favicon until the provided time.
-     *
-     * @param faviconURL Page URL for which a Favicon load has failed.
-     */
-    public void putFailed(String faviconURL) {
-        startWrite();
-
-        try {
-            FaviconsForURL container = new FaviconsForURL(0, true);
-            recordRemoved(backingMap.put(faviconURL, container));
-        } finally {
-            finishWrite();
-        }
-    }
-
-    /**
-     * Fetch a Favicon for the given URL as close as possible to the size provided.
-     * If an icon of the given size is already in the cache, it is returned.
-     * If an icon of the given size is not in the cache but a larger unscaled image does exist in
-     * the cache, we downscale the larger image to the target size and cache the result.
-     * If there is no image of the required size, null is returned.
-     *
-     * @param faviconURL The URL for which a Favicon is desired. Must not be null.
-     * @param targetSize The size of the desired favicon.
-     * @return A favicon of the requested size for the requested URL, or null if none cached.
-     */
-    public Bitmap getFaviconForDimensions(String faviconURL, int targetSize) {
-        if (faviconURL == null) {
-            Log.e(LOGTAG, "You passed a null faviconURL to getFaviconForDimensions. Don't.");
-            return null;
-        }
-
-        boolean shouldComputeColour = false;
-        boolean wasPermanent = false;
-        FaviconsForURL container;
-        final Bitmap newBitmap;
-
-        startRead();
-
-        try {
-            container = permanentBackingMap.get(faviconURL);
-            if (container == null) {
-                container = backingMap.get(faviconURL);
-                if (container == null) {
-                    // We don't have it!
-                    return null;
-                }
-            } else {
-                wasPermanent = true;
-            }
-
-            FaviconCacheElement cacheElement;
-
-            // If targetSize is -1, it means we want the largest possible icon.
-            int cacheElementIndex = (targetSize == -1) ? -1 : container.getNextHighestIndex(targetSize);
-
-            // cacheElementIndex now holds either the index of the next least largest bitmap from
-            // targetSize, or -1 if targetSize > all bitmaps.
-            if (cacheElementIndex != -1) {
-                // If cacheElementIndex is not the sentinel value, then it is a valid index into favicons.
-                cacheElement = container.favicons.get(cacheElementIndex);
-
-                if (cacheElement.invalidated) {
-                    return null;
-                }
-
-                // If we found exactly what we wanted - we're done.
-                if (cacheElement.imageSize == targetSize) {
-                    setMostRecentlyUsedWithinRead(cacheElement);
-                    return cacheElement.faviconPayload;
-                }
-            } else {
-                // We requested an image larger than all primaries. Set the element to start the search
-                // from to the element beyond the end of the array, so the search runs backwards.
-                cacheElementIndex = container.favicons.size();
-            }
-
-            // We did not find exactly what we wanted, but now have set cacheElementIndex to the index
-            // where what we want should live in the list. We now request the next least larger primary
-            // from the cache. We will downscale this to our target size.
-
-            // If there is no such primary, we'll upscale the next least smaller one instead.
-            cacheElement = container.getNextPrimary(cacheElementIndex);
-
-            if (cacheElement == null) {
-                // The primary has been invalidated! Fail! Need to get it back from the database.
-                return null;
-            }
-
-            if (targetSize == -1) {
-                // We got the biggest primary, so that's what we'll return.
-                return cacheElement.faviconPayload;
-            }
-
-            // Scaling logic...
-            Bitmap largestElementBitmap = cacheElement.faviconPayload;
-            int largestSize = cacheElement.imageSize;
-
-            if (largestSize >= targetSize) {
-                // The largest we have is larger than the target - downsize to target.
-                newBitmap = Bitmap.createScaledBitmap(largestElementBitmap, targetSize, targetSize, true);
-            } else {
-                // Our largest primary is smaller than the desired size. Upscale by a maximum of 2x.
-                // largestSize now reflects the maximum size we can upscale to.
-                largestSize *= 2;
-
-                if (largestSize >= targetSize) {
-                    // Perfect! We can upscale by less than 2x and reach the needed size. Do it.
-                    newBitmap = Bitmap.createScaledBitmap(largestElementBitmap, targetSize, targetSize, true);
-                } else {
-                    // We don't have enough information to make the target size look nonterrible. Best effort:
-                    newBitmap = Bitmap.createScaledBitmap(largestElementBitmap, largestSize, largestSize, true);
-
-                    shouldComputeColour = true;
-                }
-            }
-        } catch (Exception unhandled) {
-            // Handle any exception thrown and return the locks to a sensible state.
-
-            // Flag to prevent finally from doubly-unlocking.
-            Log.e(LOGTAG, "FaviconCache exception!", unhandled);
-            return null;
-        } finally {
-            finishRead();
-        }
-
-        startWrite();
-        try {
-            if (shouldComputeColour) {
-                // And since we failed, we'll need the dominant colour.
-                container.ensureDominantColor();
-            }
-
-            // While the image might not actually BE that size, we set the size field to the target
-            // because this is the best image you can get for a request of that size using the Favicon
-            // information provided by this website.
-            // This way, subsequent requests hit straight away.
-            FaviconCacheElement newElement = container.addSecondary(newBitmap, targetSize);
-
-            if (!wasPermanent) {
-                if (setMostRecentlyUsedWithinWrite(newElement)) {
-                    currentSize.addAndGet(newElement.sizeOf());
-                }
-            }
-        } finally {
-            finishWrite();
-        }
-
-        return newBitmap;
-    }
-
-    /**
-     * Query the cache for the dominant colour stored for the Favicon URL provided, if any.
-     *
-     * @param key The URL of the Favicon for which a dominant colour is desired.
-     * @return The cached dominant colour, or null if none is cached.
-     */
-    public int getDominantColor(String key) {
-        startRead();
-
-        try {
-            FaviconsForURL element = permanentBackingMap.get(key);
-            if (element == null) {
-                element = backingMap.get(key);
-            }
-
-            if (element == null) {
-                Log.w(LOGTAG, "Cannot compute dominant color of non-cached favicon. Cache fullness " +
-                              currentSize.get() + '/' + maxSizeBytes);
-                return 0xFFFFFF;
-            }
-
-            return element.ensureDominantColor();
-        } finally {
-            finishRead();
-        }
-    }
-
-    /**
-     * Remove all payloads stored in the given container from the LRU cache.
-     * Must be called while holding the write lock.
-     *
-     * @param wasRemoved The container to purge from the cache.
-     */
-    private void recordRemoved(FaviconsForURL wasRemoved) {
-        // If there was an existing value, strip it from the insertion-order cache.
-        if (wasRemoved == null) {
-            return;
-        }
-
-        int sizeRemoved = 0;
-
-        for (FaviconCacheElement e : wasRemoved.favicons) {
-            sizeRemoved += e.sizeOf();
-            ordering.remove(e);
-        }
-
-        currentSize.addAndGet(-sizeRemoved);
-    }
-
-    private Bitmap produceCacheableBitmap(Bitmap favicon) {
-        // Never cache the default Favicon, or the null Favicon.
-        if (favicon == Favicons.defaultFavicon || favicon == null) {
-            return null;
-        }
-
-        // Some sites serve up insanely huge Favicons (Seen 512x512 ones...)
-        // While we want to cache nice big icons, we apply a limit based on screen density for the
-        // sake of space.
-        if (favicon.getWidth() > maxCachedWidth) {
-            return Bitmap.createScaledBitmap(favicon, maxCachedWidth, maxCachedWidth, true);
-        }
-
-        return favicon;
-    }
-
-    /**
-     * Set an existing element as the most recently used element. Intended for use from read transactions. While
-     * write transactions may safely use this method, it will perform slightly worse than its unsafe counterpart below.
-     *
-     * @param element The element that is to become the most recently used one.
-     * @return true if this element already existed in the list, false otherwise. (Useful for preventing multiple-insertion.)
-     */
-    private boolean setMostRecentlyUsedWithinRead(FaviconCacheElement element) {
-        synchronized (reorderingLock) {
-            boolean contained = ordering.remove(element);
-            ordering.offer(element);
-            return contained;
-        }
-    }
-
-    /**
-     * Functionally equivalent to setMostRecentlyUsedWithinRead, but operates without taking the reordering semaphore.
-     * Only safe for use when called from a write transaction, or there is a risk of concurrent modification.
-     *
-     * @param element The element that is to become the most recently used one.
-     * @return true if this element already existed in the list, false otherwise. (Useful for preventing multiple-insertion.)
-     */
-    private boolean setMostRecentlyUsedWithinWrite(FaviconCacheElement element) {
-        boolean contained = ordering.remove(element);
-        ordering.offer(element);
-        return contained;
-    }
-
-    /**
-     * Add the provided bitmap to the cache as the only available primary for this URL.
-     * Should never be called with scaled Favicons. The input is assumed to be an unscaled Favicon.
-     *
-     * @param faviconURL The URL of the Favicon being stored.
-     * @param aFavicon The Favicon to store.
-     */
-    public void putSingleFavicon(String faviconURL, Bitmap aFavicon) {
-        Bitmap favicon = produceCacheableBitmap(aFavicon);
-        if (favicon == null) {
-            return;
-        }
-
-        // Create a fresh container for the favicons associated with this URL. Allocate extra slots
-        // in the underlying ArrayList in case multiple secondary favicons are later created.
-        // Currently set to the number of favicon sizes used in the UI, plus 1, at time of writing.
-        // Ought to be  tuned as things change for maximal performance.
-        FaviconsForURL toInsert = new FaviconsForURL(NUM_FAVICON_SIZES);
-
-        // Create the cache element for the single element we are inserting, and configure it.
-        FaviconCacheElement newElement = toInsert.addPrimary(favicon);
-
-        startWrite();
-        try {
-            // Set the new element as the most recently used one.
-            setMostRecentlyUsedWithinWrite(newElement);
-
-            currentSize.addAndGet(newElement.sizeOf());
-
-            // Update the value in the LruCache...
-            FaviconsForURL wasRemoved;
-            wasRemoved = backingMap.put(faviconURL, toInsert);
-
-            recordRemoved(wasRemoved);
-        } finally {
-            finishWrite();
-        }
-
-        cullIfRequired();
-    }
-
-    /**
-     * Set the collection of primary favicons for the given URL to the provided collection of bitmaps.
-     *
-     * @param faviconURL The URL from which the favicons originate.
-     * @param favicons A List of favicons decoded from this URL.
-     * @param permanently If true, the added favicons are never subject to eviction.
-     */
-    public void putFavicons(String faviconURL, Iterator<Bitmap> favicons, boolean permanently) {
-        // We don't know how many icons we'll have - let's just take a guess.
-        FaviconsForURL toInsert = new FaviconsForURL(5 * NUM_FAVICON_SIZES);
-        int sizeGained = 0;
-
-        while (favicons.hasNext()) {
-            Bitmap favicon = produceCacheableBitmap(favicons.next());
-            if (favicon == null) {
-                continue;
-            }
-
-            FaviconCacheElement newElement = toInsert.addPrimary(favicon);
-            sizeGained += newElement.sizeOf();
-        }
-
-        startWrite();
-        try {
-            if (permanently) {
-                permanentBackingMap.put(faviconURL, toInsert);
-                return;
-            }
-
-            for (FaviconCacheElement newElement : toInsert.favicons) {
-                setMostRecentlyUsedWithinWrite(newElement);
-            }
-
-            // In the event this insertion is being made to a key that already held a value, the subsequent recordRemoved
-            // call will subtract the size of the old value, preventing double-counting.
-            currentSize.addAndGet(sizeGained);
-
-            // Update the value in the LruCache...
-            recordRemoved(backingMap.put(faviconURL, toInsert));
-        } finally {
-            finishWrite();
-        }
-
-        cullIfRequired();
-    }
-
-    /**
-     * If cache too large, drop stuff from the cache to get the size back into the acceptable range.
-     * Otherwise, do nothing.
-     */
-    private void cullIfRequired() {
-        Log.d(LOGTAG, "Favicon cache fullness: " + currentSize.get() + '/' + maxSizeBytes);
-
-        if (currentSize.get() <= maxSizeBytes) {
-            return;
-        }
-
-        startWrite();
-        try {
-            while (currentSize.get() > maxSizeBytes) {
-                // Cull the least recently used element.
-
-                FaviconCacheElement victim;
-                victim = ordering.poll();
-
-                currentSize.addAndGet(-victim.sizeOf());
-                victim.onEvictedFromCache();
-
-                Log.d(LOGTAG, "After cull: " + currentSize.get() + '/' + maxSizeBytes);
-            }
-        } finally {
-            finishWrite();
-        }
-    }
-
-    /**
-     * Purge all elements from the FaviconCache. Handy if you want to reclaim some memory.
-     */
-    public void evictAll() {
-        startWrite();
-
-        // Note that we neither clear, nor track the size of, the permanent map.
-        try {
-            currentSize.set(0);
-            backingMap.clear();
-            ordering.clear();
-
-        } finally {
-            finishWrite();
-        }
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/cache/FaviconCacheElement.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/* 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.favicons.cache;
-
-import android.graphics.Bitmap;
-
-/**
- * Objects stored in the Favicon cache - allow for the bitmap to be tagged to indicate if it has
- * been scaled. Unscaled bitmaps are not included in the scaled-bitmap cache's size calculation.
- */
-public class FaviconCacheElement implements Comparable<FaviconCacheElement> {
-    // Was this Favicon computed via scaling another primary Favicon, or is this a primary Favicon?
-    final boolean isPrimary;
-
-    // The Favicon bitmap.
-    Bitmap faviconPayload;
-
-    // If set, faviconPayload is absent. Since the underlying ICO may contain multiple primary
-    // payloads, primary payloads are never truly deleted from the cache, but instead have their
-    // payload deleted and this flag set on their FaviconCacheElement. That way, the cache always
-    // has a record of the existence of a primary payload, even if it is no longer in the cache.
-    // This means that when a request comes in that will be best served using a primary that is in
-    // the database but no longer cached, we know that it exists and can go get it (Useful when ICO
-    // support is added).
-    volatile boolean invalidated;
-
-    final int imageSize;
-
-    // Used for LRU pruning.
-    final FaviconsForURL backpointer;
-
-    public FaviconCacheElement(Bitmap payload, boolean primary, int size, FaviconsForURL backpointer) {
-        this.faviconPayload = payload;
-        this.isPrimary = primary;
-        this.imageSize = size;
-        this.backpointer = backpointer;
-    }
-
-    public FaviconCacheElement(Bitmap faviconPayload, boolean isPrimary, FaviconsForURL backpointer) {
-        this.faviconPayload = faviconPayload;
-        this.isPrimary = isPrimary;
-        this.backpointer = backpointer;
-
-        if (faviconPayload != null) {
-            imageSize = faviconPayload.getWidth();
-        } else {
-            imageSize = 0;
-        }
-    }
-
-    public int sizeOf() {
-        if (invalidated) {
-            return 0;
-        }
-        return faviconPayload.getRowBytes() * faviconPayload.getHeight();
-    }
-
-    /**
-     * Establish an ordering on FaviconCacheElements based on size and validity. An element is
-     * considered "greater than" another if it is valid and the other is not, or if it contains a
-     * larger payload.
-     *
-     * @param another The FaviconCacheElement to compare to this one.
-     * @return -1 if this element is less than the given one, 1 if the other one is larger than this
-     *         and 0 if both are of equal value.
-     */
-    @Override
-    public int compareTo(FaviconCacheElement another) {
-        if (invalidated && !another.invalidated) {
-            return -1;
-        }
-
-        if (!invalidated && another.invalidated) {
-            return 1;
-        }
-
-        if (invalidated) {
-            return 0;
-        }
-
-        final int w1 = imageSize;
-        final int w2 = another.imageSize;
-        if (w1 > w2) {
-            return 1;
-        }
-
-        if (w2 > w1) {
-            return -1;
-        }
-        return 0;
-    }
-
-    /**
-     * Called when this element is evicted from the cache.
-     *
-     * If primary, drop the payload and set invalid. If secondary, just unlink from parent node.
-     */
-    public void onEvictedFromCache() {
-        if (isPrimary) {
-            // So we keep a record of which primaries exist in the database for this URL, we
-            // don't actually delete the entry for primaries. Instead, we delete their payload
-            // and flag them as invalid. This way, we can later figure out that what a request
-            // really want is one of the primaries that have been dropped from the cache, and we
-            // can go get it.
-            invalidated = true;
-            faviconPayload = null;
-        } else {
-            // Secondaries don't matter - just delete them.
-            if (backpointer == null) {
-                return;
-            }
-            backpointer.favicons.remove(this);
-        }
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/cache/FaviconsForURL.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/* 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.favicons.cache;
-
-import android.graphics.Bitmap;
-import android.util.Log;
-import org.mozilla.gecko.gfx.BitmapUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-public class FaviconsForURL {
-    private static final String LOGTAG = "FaviconForURL";
-
-    private volatile int dominantColor = -1;
-
-    final long downloadTimestamp;
-    final ArrayList<FaviconCacheElement> favicons;
-
-    public final boolean hasFailed;
-
-    public FaviconsForURL(int size) {
-        this(size, false);
-    }
-
-    public FaviconsForURL(int size, boolean failed) {
-        hasFailed = failed;
-        downloadTimestamp = System.currentTimeMillis();
-        favicons = new ArrayList<FaviconCacheElement>(size);
-    }
-
-    public FaviconCacheElement addSecondary(Bitmap favicon, int imageSize) {
-        return addInternal(favicon, false, imageSize);
-    }
-
-    public FaviconCacheElement addPrimary(Bitmap favicon) {
-        return addInternal(favicon, true, favicon.getWidth());
-    }
-
-    private FaviconCacheElement addInternal(Bitmap favicon, boolean isPrimary, int imageSize) {
-        FaviconCacheElement c = new FaviconCacheElement(favicon, isPrimary, imageSize, this);
-
-        int index = Collections.binarySearch(favicons, c);
-
-        // We've already got an equivalent one. We don't care about this new one. This only occurs in certain obscure
-        // case conditions.
-        if (index >= 0) {
-            return favicons.get(index);
-        }
-
-        // binarySearch returns -x - 1 where x is the insertion point of the element. Convert
-        // this to the actual insertion point..
-        index++;
-        index = -index;
-        favicons.add(index, c);
-
-        return c;
-    }
-
-    /**
-     * Get the index of the smallest image in this collection larger than or equal to
-     * the given target size.
-     *
-     * @param targetSize Minimum size for the desired result.
-     * @return The index of the smallest image larger than the target size, or -1 if none exists.
-     */
-    public int getNextHighestIndex(int targetSize) {
-        // Create a dummy object to hold the target value for comparable.
-        FaviconCacheElement dummy = new FaviconCacheElement(null, false, targetSize, null);
-
-        int index = Collections.binarySearch(favicons, dummy);
-
-        // The search routine returns the index of an element equal to dummy, if present.
-        // Otherwise, it returns -x - 1, where x is the index in the ArrayList where dummy would be
-        // inserted if the list were to remain sorted.
-        if (index < 0) {
-            index++;
-            index = -index;
-        }
-
-        // index is now 'x', as described above.
-
-        // The routine will return favicons.size() as the index iff dummy is larger than all elements
-        // present (So the "index at which it should be inserted" is the index after the end.
-        // In this case, we set the sentinel value -1 to indicate that we just requested something
-        // larger than all primaries.
-        if (index == favicons.size()) {
-            index = -1;
-        }
-
-        return index;
-    }
-
-    /**
-     * Get the next valid primary icon from this collection, starting at the given index.
-     * If the appropriate icon is found, but is invalid, we return null - the proper response is to
-     * reacquire the primary from the database.
-     * If no icon is found, the search is repeated going backwards from the start index to find any
-     * primary at all (The input index may be a secondary which is larger than the actual available
-     * primary.)
-     *
-     * @param fromIndex The index into favicons from which to start the search.
-     * @return The FaviconCacheElement of the next valid primary from the given index. If none exists,
-     *         then returns the previous valid primary. If none exists, returns null (Insanity.).
-     */
-    public FaviconCacheElement getNextPrimary(final int fromIndex) {
-        final int numIcons = favicons.size();
-
-        int searchIndex = fromIndex;
-        while (searchIndex < numIcons) {
-            FaviconCacheElement element = favicons.get(searchIndex);
-
-            if (element.isPrimary) {
-                if (element.invalidated) {
-                    // We return null here, despite the possible existence of other primaries,
-                    // because we know the most suitable primary for this request exists, but is
-                    // no longer in the cache. By returning null, we cause the caller to load the
-                    // missing primary from the database and call again.
-                    return null;
-                }
-                return element;
-            }
-            searchIndex++;
-        }
-
-        // No larger primary available. Let's look for smaller ones...
-        searchIndex = fromIndex - 1;
-        while (searchIndex >= 0) {
-            FaviconCacheElement element = favicons.get(searchIndex);
-
-            if (element.isPrimary) {
-                if (element.invalidated) {
-                    return null;
-                }
-                return element;
-            }
-            searchIndex--;
-        }
-
-        Log.e(LOGTAG, "No primaries found in Favicon cache structure. This is madness!");
-
-        return null;
-    }
-
-    /**
-     * Ensure the dominant colour field is populated for this favicon.
-     */
-    public int ensureDominantColor() {
-        if (dominantColor == -1) {
-            // Find a payload, any payload, that is not invalidated.
-            for (FaviconCacheElement element : favicons) {
-                if (!element.invalidated) {
-                    dominantColor = BitmapUtils.getDominantColor(element.faviconPayload);
-                    return dominantColor;
-                }
-            }
-            dominantColor = 0xFFFFFF;
-        }
-
-        return dominantColor;
-    }
-}
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/decoders/FaviconDecoder.java
+++ b/mobile/android/base/java/org/mozilla/gecko/favicons/decoders/FaviconDecoder.java
@@ -1,14 +1,15 @@
 /* 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.favicons.decoders;
 
+import android.content.Context;
 import android.graphics.Bitmap;
 import android.util.Base64;
 import android.util.Log;
 
 import org.mozilla.gecko.gfx.BitmapUtils;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
@@ -80,17 +81,17 @@ public class FaviconDecoder {
      * given range does not contain a bitmap we know how to decode.
      *
      * @param buffer Byte array containing the favicon to decode.
      * @param offset The index of the first byte in the array of the region of interest.
      * @param length The length of the region in the array to decode.
      * @return The decoded version of the bitmap in the described region, or null if none can be
      *         decoded.
      */
-    public static LoadFaviconResult decodeFavicon(byte[] buffer, int offset, int length) {
+    public static LoadFaviconResult decodeFavicon(Context context, byte[] buffer, int offset, int length) {
         LoadFaviconResult result;
         if (isDecodableByAndroid(buffer, offset)) {
             result = new LoadFaviconResult();
             result.offset = offset;
             result.length = length;
             result.isICO = false;
 
             Bitmap decodedImage = BitmapUtils.decodeByteArray(buffer, offset, length);
@@ -103,28 +104,28 @@ public class FaviconDecoder {
             // buffer -- worst case, each of our buffers will be twice the necessary size.
             result.bitmapsDecoded = new SingleBitmapIterator(decodedImage);
             result.faviconBytes = buffer;
 
             return result;
         }
 
         // If it's not decodable by Android, it might be an ICO. Let's try.
-        ICODecoder decoder = new ICODecoder(buffer, offset, length);
+        ICODecoder decoder = new ICODecoder(context, buffer, offset, length);
 
         result = decoder.decode();
 
         if (result == null) {
             return null;
         }
 
         return result;
     }
 
-    public static LoadFaviconResult decodeDataURI(String uri) {
+    public static LoadFaviconResult decodeDataURI(Context context, String uri) {
         if (uri == null) {
             Log.w(LOG_TAG, "Can't decode null data: URI.");
             return null;
         }
 
         if (!uri.startsWith("data:image/")) {
             // Can't decode non-image data: URI.
             return null;
@@ -135,25 +136,25 @@ public class FaviconDecoder {
         if (offset == 0) {
             Log.w(LOG_TAG, "No ',' in data: URI; malformed?");
             return null;
         }
 
         try {
             String base64 = uri.substring(offset);
             byte[] raw = Base64.decode(base64, Base64.DEFAULT);
-            return decodeFavicon(raw);
+            return decodeFavicon(context, raw);
         } catch (Exception e) {
             Log.w(LOG_TAG, "Couldn't decode data: URI.", e);
             return null;
         }
     }
 
-    public static LoadFaviconResult decodeFavicon(byte[] buffer) {
-        return decodeFavicon(buffer, 0, buffer.length);
+    public static LoadFaviconResult decodeFavicon(Context context, byte[] buffer) {
+        return decodeFavicon(context, buffer, 0, buffer.length);
     }
 
     /**
      * Iterator to hold a single bitmap.
      */
     static class SingleBitmapIterator implements Iterator<Bitmap> {
         private Bitmap bitmap;
 
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/decoders/ICODecoder.java
+++ b/mobile/android/base/java/org/mozilla/gecko/favicons/decoders/ICODecoder.java
@@ -1,23 +1,24 @@
 /* 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.favicons.decoders;
 
+import android.content.Context;
 import android.graphics.Bitmap;
-import org.mozilla.gecko.favicons.Favicons;
-import org.mozilla.gecko.gfx.BitmapUtils;
-
 import android.util.SparseArray;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.R;
+
 /**
  * Utility class for determining the region of a provided array which contains the largest bitmap,
  * assuming the provided array is a valid ICO and the bitmap desired is square, and for pruning
  * unwanted entries from ICO files, if desired.
  *
  * An ICO file is a container format that may hold up to 255 images in either BMP or PNG format.
  * A mixture of image types may not exist.
  *
@@ -82,21 +83,24 @@ public class ICODecoder implements Itera
 
     // The region of the decodand to decode.
     private int offset;
     private int len;
 
     IconDirectoryEntry[] iconDirectory;
     private boolean isValid;
     private boolean hasDecoded;
+    private int largestFaviconSize;
 
-    public ICODecoder(byte[] decodand, int offset, int len) {
+    public ICODecoder(Context context, byte[] decodand, int offset, int len) {
         this.decodand = decodand;
         this.offset = offset;
         this.len = len;
+        this.largestFaviconSize = context.getResources()
+                .getDimensionPixelSize(R.dimen.favicon_largest_interesting_size);
     }
 
     /**
      * Decode the Icon Directory for this ICO and store the result in iconDirectory.
      *
      * @return true if ICO decoding was considered to probably be a success, false if it certainly
      *         was a failure.
      */
@@ -158,17 +162,17 @@ public class ICODecoder implements Itera
             // Decode the Icon Directory Entry at this offset.
             IconDirectoryEntry newEntry = IconDirectoryEntry.createFromBuffer(decodand, offset, len, bufferIndex);
             newEntry.index = i;
 
             if (newEntry.isErroneous) {
                 continue;
             }
 
-            if (newEntry.width > Favicons.largestFaviconSize) {
+            if (newEntry.width > largestFaviconSize) {
                 // If we already have a smaller image larger than the maximum size of interest, we
                 // don't care about the new one which is larger than the smallest image larger than
                 // the maximum size.
                 if (newEntry.width >= minimumMaximum) {
                     continue;
                 }
 
                 // Remove the previous minimum-maximum.
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/decoders/LoadFaviconResult.java
+++ b/mobile/android/base/java/org/mozilla/gecko/favicons/decoders/LoadFaviconResult.java
@@ -3,24 +3,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.favicons.decoders;
 
 import android.graphics.Bitmap;
 import android.util.Log;
 import android.util.SparseArray;
 
-import org.mozilla.gecko.favicons.Favicons;
-
 import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Class representing the result of loading a favicon.
  * This operation will produce either a collection of favicons, a single favicon, or no favicon.
  * It is necessary to model single favicons differently to a collection of one favicon (An entity
  * that may not exist with this scheme) since the in-database representation of these things differ.
  * (In particular, collections of favicons are stored in encoded ICO format, whereas single icons are
  * stored as decoded bitmap blobs.)
@@ -90,19 +87,45 @@ public class LoadFaviconResult {
             // It's possible to receive null, most likely due to OOM or a zero-sized image,
             // from BitmapUtils.decodeByteArray(byte[], int, int, BitmapFactory.Options)
             if (b != null) {
                 iconMap.put(b.getWidth(), b);
                 sizes.add(b.getWidth());
             }
         }
 
-        int bestSize = Favicons.selectBestSizeFromList(sizes, targetWidthAndHeight);
+        int bestSize = selectBestSizeFromList(sizes, targetWidthAndHeight);
 
         if (bestSize == -1) {
             // No icons found: this could occur if we weren't able to process any of the
             // supplied icons.
             return null;
         }
 
         return iconMap.get(bestSize);
     }
+
+    /**
+     * Select the closest icon size from a list of icon sizes.
+     * We just find the first icon that is larger than the preferred size if available, or otherwise select the
+     * largest icon (if all icons are smaller than the preferred size).
+     *
+     * @return The closest icon size, or -1 if no sizes are supplied.
+     */
+    public static int selectBestSizeFromList(final List<Integer> sizes, final int preferredSize) {
+        if (sizes.isEmpty()) {
+            // This isn't ideal, however current code assumes this as an error value for now.
+            return -1;
+        }
+
+        Collections.sort(sizes);
+
+        for (int size : sizes) {
+            if (size >= preferredSize) {
+                return size;
+            }
+        }
+
+        // If all icons are smaller than the preferred size then we don't have an icon
+        // selected yet, therefore just take the largest (last) icon.
+        return sizes.get(sizes.size() - 1);
+    }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/home/TwoLinePageRow.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/TwoLinePageRow.java
@@ -3,44 +3,42 @@
  * 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 java.lang.ref.WeakReference;
 import java.util.concurrent.Future;
 
-import org.mozilla.gecko.AboutPages;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.distribution.PartnerBookmarksProviderProxy;
-import org.mozilla.gecko.icons.IconCallback;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.reader.SavedReaderViewHelper;
-import org.mozilla.gecko.reader.ReaderModeUtils;
-import org.mozilla.gecko.Tab;
-import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserContract.URLColumns;
-import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
-import org.mozilla.gecko.widget.FaviconView;
-
 import android.content.Context;
 import android.database.Cursor;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.widget.ImageView;
-import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import org.mozilla.gecko.AboutPages;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.Tab;
+import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.db.BrowserContract.Combined;
+import org.mozilla.gecko.db.BrowserContract.URLColumns;
+import org.mozilla.gecko.distribution.PartnerBookmarksProviderProxy;
+import org.mozilla.gecko.icons.IconDescriptor;
+import org.mozilla.gecko.icons.IconResponse;
+import org.mozilla.gecko.icons.Icons;
+import org.mozilla.gecko.reader.ReaderModeUtils;
+import org.mozilla.gecko.reader.SavedReaderViewHelper;
+import org.mozilla.gecko.widget.FaviconView;
+
 public class TwoLinePageRow extends LinearLayout
                             implements Tabs.OnTabsChangedListener {
 
     protected static final int NO_ICON = 0;
 
     private final TextView mTitle;
     private final TextView mUrl;
     private final ImageView mStatusIcon;
--- a/mobile/android/base/java/org/mozilla/gecko/icons/loader/ContentProviderLoader.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/loader/ContentProviderLoader.java
@@ -54,43 +54,43 @@ public class ContentProviderLoader imple
         }
 
         try {
             if (!cursor.moveToFirst()) {
                 return null;
             }
 
             // Try the touch icon first. It has a higher resolution usually.
-            Bitmap icon = decodeFromCursor(cursor, PartnerBookmarksProviderProxy.PartnerContract.TOUCHICON, targetSize);
+            Bitmap icon = decodeFromCursor(request.getContext(), cursor, PartnerBookmarksProviderProxy.PartnerContract.TOUCHICON, targetSize);
             if (icon != null) {
                 return IconResponse.create(icon);
             }
 
-            icon = decodeFromCursor(cursor, PartnerBookmarksProviderProxy.PartnerContract.FAVICON, targetSize);
+            icon = decodeFromCursor(request.getContext(), cursor, PartnerBookmarksProviderProxy.PartnerContract.FAVICON, targetSize);
             if (icon != null) {
                 return IconResponse.create(icon);
             }
         } finally {
             cursor.close();
         }
 
         return null;
     }
 
-    private Bitmap decodeFromCursor(Cursor cursor, String column, int targetWidthAndHeight) {
+    private Bitmap decodeFromCursor(Context context, Cursor cursor, String column, int targetWidthAndHeight) {
         final int index = cursor.getColumnIndex(column);
         if (index == -1) {
             return null;
         }
 
         if (cursor.isNull(index)) {
             return null;
         }
 
         final byte[] data = cursor.getBlob(index);
-        LoadFaviconResult result = FaviconDecoder.decodeFavicon(data, 0, data.length);
+        LoadFaviconResult result = FaviconDecoder.decodeFavicon(context, data, 0, data.length);
         if (result == null) {
             return null;
         }
 
         return result.getBestBitmap(targetWidthAndHeight);
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/icons/loader/DataUriLoader.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/loader/DataUriLoader.java
@@ -20,17 +20,17 @@ public class DataUriLoader implements Ic
     @Override
     public IconResponse load(IconRequest request) {
         final String iconUrl = request.getBestIcon().getUrl();
 
         if (!iconUrl.startsWith("data:image/")) {
             return null;
         }
 
-        LoadFaviconResult loadFaviconResult = FaviconDecoder.decodeDataURI(iconUrl);
+        LoadFaviconResult loadFaviconResult = FaviconDecoder.decodeDataURI(request.getContext(), iconUrl);
         if (loadFaviconResult == null) {
             return null;
         }
 
         return IconResponse.create(
                 loadFaviconResult.getBestBitmap(request.getTargetSize()));
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/icons/loader/IconDownloader.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/loader/IconDownloader.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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.icons.loader;
 
+import android.content.Context;
 import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
 import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
 import org.mozilla.gecko.icons.IconRequest;
 import org.mozilla.gecko.icons.IconResponse;
@@ -49,17 +50,17 @@ public class IconDownloader implements I
 
         final String iconUrl = request.getBestIcon().getUrl();
 
         if (!StringUtils.isHttpOrHttps(iconUrl)) {
             return null;
         }
 
         try {
-            LoadFaviconResult result = downloadAndDecodeImage(iconUrl);
+            LoadFaviconResult result = downloadAndDecodeImage(request.getContext(), iconUrl);
             if (result == null) {
                 return null;
             }
 
             return IconResponse.createFromNetwork(
                     result.getBestBitmap(request.getTargetSize()),
                     iconUrl);
         } catch (Exception e) {
@@ -78,29 +79,28 @@ public class IconDownloader implements I
      * @return A LoadFaviconResult containing the bitmap(s) extracted from the downloaded file, or
      *         null if no or corrupt data was received.
      * @throws IOException If attempts to fully read the stream result in such an exception, such as
      *                     in the event of a transient connection failure.
      * @throws URISyntaxException If the underlying call to tryDownload retries and raises such an
      *                            exception trying a fallback URL.
      */
     @VisibleForTesting
-    LoadFaviconResult downloadAndDecodeImage(String targetFaviconURL) throws IOException, URISyntaxException {
+    LoadFaviconResult downloadAndDecodeImage(Context context, String targetFaviconURL) throws IOException, URISyntaxException {
         // Try the URL we were given.
         HttpURLConnection connection = tryDownload(targetFaviconURL);
         if (connection == null) {
             return null;
         }
 
         InputStream stream = null;
 
         // Decode the image from the fetched response.
         try {
-            stream = connection.getInputStream();
-            return decodeImageFromResponse(connection.getInputStream(), connection.getHeaderFieldInt("Content-Length", -1));
+            return decodeImageFromResponse(context, connection.getInputStream(), connection.getHeaderFieldInt("Content-Length", -1));
         } finally {
             // Close the stream and free related resources.
             IOUtils.safeStreamClose(stream);
             connection.disconnect();
         }
     }
 
     /**
@@ -185,17 +185,17 @@ public class IconDownloader implements I
      *
      * @param stream to decode
      * @param contentLength as reported by the server (or -1)
      * @return A LoadFaviconResult containing the bitmap(s) extracted from the downloaded file, or
      *         null if no or corrupt data were received.
      * @throws IOException If attempts to fully read the stream result in such an exception, such as
      *                     in the event of a transient connection failure.
      */
-    private LoadFaviconResult decodeImageFromResponse(InputStream stream, int contentLength) throws IOException {
+    private LoadFaviconResult decodeImageFromResponse(Context context, InputStream stream, int contentLength) throws IOException {
         // This may not be provided, but if it is, it's useful.
         int bufferSize;
         if (contentLength > 0) {
             // The size was reported and sane, so let's use that.
             // Integer overflow should not be a problem for Favicon sizes...
             bufferSize = contentLength + 1;
         } else {
             // No declared size, so guess and reallocate later if it turns out to be too small.
@@ -204,11 +204,11 @@ public class IconDownloader implements I
 
         // Read the InputStream into a byte[].
         IOUtils.ConsumedInputStream result = IOUtils.readFully(stream, bufferSize);
         if (result == null) {
             return null;
         }
 
         // Having downloaded the image, decode it.
-        return FaviconDecoder.decodeFavicon(result.getData(), 0, result.consumedLength);
+        return FaviconDecoder.decodeFavicon(context, result.getData(), 0, result.consumedLength);
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/icons/loader/LegacyLoader.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/loader/LegacyLoader.java
@@ -46,16 +46,16 @@ public class LegacyLoader implements Ico
         // We ask the database for the favicon URL and ignore the icon URL in the request object:
         // As we are not updating the database anymore the icon might be stored under a different URL.
         final String legacyFaviconUrl = db.getFaviconURLFromPageURL(contentResolver, request.getPageUrl());
         if (legacyFaviconUrl == null) {
             // No URL -> Nothing to load.
             return null;
         }
 
-        final LoadFaviconResult result = db.getFaviconForUrl(context.getContentResolver(), legacyFaviconUrl);
+        final LoadFaviconResult result = db.getFaviconForUrl(context, context.getContentResolver(), legacyFaviconUrl);
         if (result == null) {
             return null;
         }
 
         return result.getBestBitmap(request.getTargetSize());
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/promotion/HomeScreenPrompt.java
+++ b/mobile/android/base/java/org/mozilla/gecko/promotion/HomeScreenPrompt.java
@@ -6,32 +6,30 @@
 package org.mozilla.gecko.promotion;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.Locales;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.db.UrlAnnotations;
-import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.icons.IconCallback;
 import org.mozilla.gecko.icons.IconResponse;
 import org.mozilla.gecko.icons.Icons;
 import org.mozilla.gecko.Experiments;
 import org.mozilla.gecko.util.ThreadUtils;
 
 /**
  * Prompt to promote adding the current website to the home screen.
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -370,28 +370,21 @@ gbjar.sources += ['java/org/mozilla/geck
     'dlc/StudyAction.java',
     'dlc/SyncAction.java',
     'dlc/VerifyAction.java',
     'DoorHangerPopup.java',
     'DownloadsIntegration.java',
     'DynamicToolbar.java',
     'EditBookmarkDialog.java',
     'Experiments.java',
-    'favicons/cache/FaviconCache.java',
-    'favicons/cache/FaviconCacheElement.java',
-    'favicons/cache/FaviconsForURL.java',
     'favicons/decoders/FaviconDecoder.java',
     'favicons/decoders/ICODecoder.java',
     'favicons/decoders/IconDirectoryEntry.java',
     'favicons/decoders/LoadFaviconResult.java',
     'favicons/FaviconGenerator.java',
-    'favicons/Favicons.java',
-    'favicons/LoadFaviconTask.java',
-    'favicons/OnFaviconLoadedListener.java',
-    'favicons/RemoteFavicon.java',
     'feeds/action/CheckForUpdatesAction.java',
     'feeds/action/EnrollSubscriptionsAction.java',
     'feeds/action/FeedAction.java',
     'feeds/action/SetupAlarmsAction.java',
     'feeds/action/SubscribeToFeedAction.java',
     'feeds/action/WithdrawSubscriptionsAction.java',
     'feeds/ContentNotificationsDelegate.java',
     'feeds/FeedAlarmReceiver.java',
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconDownloader.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconDownloader.java
@@ -1,26 +1,29 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.icons.loader;
 
+import android.content.Context;
+
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.mozilla.gecko.icons.IconDescriptor;
 import org.mozilla.gecko.icons.IconRequest;
 import org.mozilla.gecko.icons.IconResponse;
 import org.mozilla.gecko.icons.Icons;
 import org.mozilla.gecko.icons.storage.FailureCache;
 import org.robolectric.RuntimeEnvironment;
 
 import java.net.HttpURLConnection;
 
+import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 @RunWith(TestRunner.class)
@@ -39,17 +42,17 @@ public class TestIconDownloader {
                         "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAEklEQVR4AWP4z8AAxCDiP8N/AB3wBPxcBee7AAAAAElFTkSuQmCC"))
                 .build();
 
         final IconDownloader downloader = spy(new IconDownloader());
         IconResponse response = downloader.load(request);
 
         Assert.assertNull(response);
 
-        verify(downloader, never()).downloadAndDecodeImage(anyString());
+        verify(downloader, never()).downloadAndDecodeImage(any(Context.class), anyString());
         verify(downloader, never()).connectTo(anyString());
     }
 
     /**
      * Scenario: Request contains an URL and server returns 301 with location header (always the same URL).
      *
      * Verify that:
      *  * Download code stops and does not loop forever.