mobile/android/base/favicons/cache/FaviconsForURL.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/favicons/cache/FaviconsForURL.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,164 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +package org.mozilla.gecko.favicons.cache;
     1.9 +
    1.10 +import android.graphics.Bitmap;
    1.11 +import android.util.Log;
    1.12 +import org.mozilla.gecko.gfx.BitmapUtils;
    1.13 +
    1.14 +import java.util.ArrayList;
    1.15 +import java.util.Collections;
    1.16 +
    1.17 +public class FaviconsForURL {
    1.18 +    private static final String LOGTAG = "FaviconForURL";
    1.19 +
    1.20 +    private volatile int dominantColor = -1;
    1.21 +
    1.22 +    final long downloadTimestamp;
    1.23 +    final ArrayList<FaviconCacheElement> favicons;
    1.24 +
    1.25 +    public final boolean hasFailed;
    1.26 +
    1.27 +    public FaviconsForURL(int size) {
    1.28 +        this(size, false);
    1.29 +    }
    1.30 +
    1.31 +    public FaviconsForURL(int size, boolean failed) {
    1.32 +        hasFailed = failed;
    1.33 +        downloadTimestamp = System.currentTimeMillis();
    1.34 +        favicons = new ArrayList<FaviconCacheElement>(size);
    1.35 +    }
    1.36 +
    1.37 +    public FaviconCacheElement addSecondary(Bitmap favicon, int imageSize) {
    1.38 +        return addInternal(favicon, false, imageSize);
    1.39 +    }
    1.40 +
    1.41 +    public FaviconCacheElement addPrimary(Bitmap favicon) {
    1.42 +        return addInternal(favicon, true, favicon.getWidth());
    1.43 +    }
    1.44 +
    1.45 +    private FaviconCacheElement addInternal(Bitmap favicon, boolean isPrimary, int imageSize) {
    1.46 +        FaviconCacheElement c = new FaviconCacheElement(favicon, isPrimary, imageSize, this);
    1.47 +
    1.48 +        int index = Collections.binarySearch(favicons, c);
    1.49 +
    1.50 +        // We've already got an equivalent one. We don't care about this new one. This only occurs in certain obscure
    1.51 +        // case conditions.
    1.52 +        if (index >= 0) {
    1.53 +            return favicons.get(index);
    1.54 +        }
    1.55 +
    1.56 +        // binarySearch returns -x - 1 where x is the insertion point of the element. Convert
    1.57 +        // this to the actual insertion point..
    1.58 +        index++;
    1.59 +        index = -index;
    1.60 +        favicons.add(index, c);
    1.61 +
    1.62 +        return c;
    1.63 +    }
    1.64 +
    1.65 +    /**
    1.66 +     * Get the index of the smallest image in this collection larger than or equal to
    1.67 +     * the given target size.
    1.68 +     *
    1.69 +     * @param targetSize Minimum size for the desired result.
    1.70 +     * @return The index of the smallest image larger than the target size, or -1 if none exists.
    1.71 +     */
    1.72 +    public int getNextHighestIndex(int targetSize) {
    1.73 +        // Create a dummy object to hold the target value for comparable.
    1.74 +        FaviconCacheElement dummy = new FaviconCacheElement(null, false, targetSize, null);
    1.75 +
    1.76 +        int index = Collections.binarySearch(favicons, dummy);
    1.77 +
    1.78 +        // The search routine returns the index of an element equal to dummy, if present.
    1.79 +        // Otherwise, it returns -x - 1, where x is the index in the ArrayList where dummy would be
    1.80 +        // inserted if the list were to remain sorted.
    1.81 +        if (index < 0) {
    1.82 +            index++;
    1.83 +            index = -index;
    1.84 +        }
    1.85 +
    1.86 +        // index is now 'x', as described above.
    1.87 +
    1.88 +        // The routine will return favicons.size() as the index iff dummy is larger than all elements
    1.89 +        // present (So the "index at which it should be inserted" is the index after the end.
    1.90 +        // In this case, we set the sentinel value -1 to indicate that we just requested something
    1.91 +        // larger than all primaries.
    1.92 +        if (index == favicons.size()) {
    1.93 +            index = -1;
    1.94 +        }
    1.95 +
    1.96 +        return index;
    1.97 +    }
    1.98 +
    1.99 +    /**
   1.100 +     * Get the next valid primary icon from this collection, starting at the given index.
   1.101 +     * If the appropriate icon is found, but is invalid, we return null - the proper response is to
   1.102 +     * reacquire the primary from the database.
   1.103 +     * If no icon is found, the search is repeated going backwards from the start index to find any
   1.104 +     * primary at all (The input index may be a secondary which is larger than the actual available
   1.105 +     * primary.)
   1.106 +     *
   1.107 +     * @param fromIndex The index into favicons from which to start the search.
   1.108 +     * @return The FaviconCacheElement of the next valid primary from the given index. If none exists,
   1.109 +     *         then returns the previous valid primary. If none exists, returns null (Insanity.).
   1.110 +     */
   1.111 +    public FaviconCacheElement getNextPrimary(final int fromIndex) {
   1.112 +        final int numIcons = favicons.size();
   1.113 +
   1.114 +        int searchIndex = fromIndex;
   1.115 +        while (searchIndex < numIcons) {
   1.116 +            FaviconCacheElement element = favicons.get(searchIndex);
   1.117 +
   1.118 +            if (element.isPrimary) {
   1.119 +                if (element.invalidated) {
   1.120 +                    // We return null here, despite the possible existence of other primaries,
   1.121 +                    // because we know the most suitable primary for this request exists, but is
   1.122 +                    // no longer in the cache. By returning null, we cause the caller to load the
   1.123 +                    // missing primary from the database and call again.
   1.124 +                    return null;
   1.125 +                }
   1.126 +                return element;
   1.127 +            }
   1.128 +            searchIndex++;
   1.129 +        }
   1.130 +
   1.131 +        // No larger primary available. Let's look for smaller ones...
   1.132 +        searchIndex = fromIndex - 1;
   1.133 +        while (searchIndex >= 0) {
   1.134 +            FaviconCacheElement element = favicons.get(searchIndex);
   1.135 +
   1.136 +            if (element.isPrimary) {
   1.137 +                if (element.invalidated) {
   1.138 +                    return null;
   1.139 +                }
   1.140 +                return element;
   1.141 +            }
   1.142 +            searchIndex--;
   1.143 +        }
   1.144 +
   1.145 +        Log.e(LOGTAG, "No primaries found in Favicon cache structure. This is madness!");
   1.146 +
   1.147 +        return null;
   1.148 +    }
   1.149 +
   1.150 +    /**
   1.151 +     * Ensure the dominant colour field is populated for this favicon.
   1.152 +     */
   1.153 +    public int ensureDominantColor() {
   1.154 +        if (dominantColor == -1) {
   1.155 +            // Find a payload, any payload, that is not invalidated.
   1.156 +            for (FaviconCacheElement element : favicons) {
   1.157 +                if (!element.invalidated) {
   1.158 +                    dominantColor = BitmapUtils.getDominantColor(element.faviconPayload);
   1.159 +                    return dominantColor;
   1.160 +                }
   1.161 +            }
   1.162 +            dominantColor = 0xFFFFFF;
   1.163 +        }
   1.164 +
   1.165 +        return dominantColor;
   1.166 +    }
   1.167 +}

mercurial