Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 package org.mozilla.gecko.favicons.cache;
7 import android.graphics.Bitmap;
8 import android.util.Log;
9 import org.mozilla.gecko.gfx.BitmapUtils;
11 import java.util.ArrayList;
12 import java.util.Collections;
14 public class FaviconsForURL {
15 private static final String LOGTAG = "FaviconForURL";
17 private volatile int dominantColor = -1;
19 final long downloadTimestamp;
20 final ArrayList<FaviconCacheElement> favicons;
22 public final boolean hasFailed;
24 public FaviconsForURL(int size) {
25 this(size, false);
26 }
28 public FaviconsForURL(int size, boolean failed) {
29 hasFailed = failed;
30 downloadTimestamp = System.currentTimeMillis();
31 favicons = new ArrayList<FaviconCacheElement>(size);
32 }
34 public FaviconCacheElement addSecondary(Bitmap favicon, int imageSize) {
35 return addInternal(favicon, false, imageSize);
36 }
38 public FaviconCacheElement addPrimary(Bitmap favicon) {
39 return addInternal(favicon, true, favicon.getWidth());
40 }
42 private FaviconCacheElement addInternal(Bitmap favicon, boolean isPrimary, int imageSize) {
43 FaviconCacheElement c = new FaviconCacheElement(favicon, isPrimary, imageSize, this);
45 int index = Collections.binarySearch(favicons, c);
47 // We've already got an equivalent one. We don't care about this new one. This only occurs in certain obscure
48 // case conditions.
49 if (index >= 0) {
50 return favicons.get(index);
51 }
53 // binarySearch returns -x - 1 where x is the insertion point of the element. Convert
54 // this to the actual insertion point..
55 index++;
56 index = -index;
57 favicons.add(index, c);
59 return c;
60 }
62 /**
63 * Get the index of the smallest image in this collection larger than or equal to
64 * the given target size.
65 *
66 * @param targetSize Minimum size for the desired result.
67 * @return The index of the smallest image larger than the target size, or -1 if none exists.
68 */
69 public int getNextHighestIndex(int targetSize) {
70 // Create a dummy object to hold the target value for comparable.
71 FaviconCacheElement dummy = new FaviconCacheElement(null, false, targetSize, null);
73 int index = Collections.binarySearch(favicons, dummy);
75 // The search routine returns the index of an element equal to dummy, if present.
76 // Otherwise, it returns -x - 1, where x is the index in the ArrayList where dummy would be
77 // inserted if the list were to remain sorted.
78 if (index < 0) {
79 index++;
80 index = -index;
81 }
83 // index is now 'x', as described above.
85 // The routine will return favicons.size() as the index iff dummy is larger than all elements
86 // present (So the "index at which it should be inserted" is the index after the end.
87 // In this case, we set the sentinel value -1 to indicate that we just requested something
88 // larger than all primaries.
89 if (index == favicons.size()) {
90 index = -1;
91 }
93 return index;
94 }
96 /**
97 * Get the next valid primary icon from this collection, starting at the given index.
98 * If the appropriate icon is found, but is invalid, we return null - the proper response is to
99 * reacquire the primary from the database.
100 * If no icon is found, the search is repeated going backwards from the start index to find any
101 * primary at all (The input index may be a secondary which is larger than the actual available
102 * primary.)
103 *
104 * @param fromIndex The index into favicons from which to start the search.
105 * @return The FaviconCacheElement of the next valid primary from the given index. If none exists,
106 * then returns the previous valid primary. If none exists, returns null (Insanity.).
107 */
108 public FaviconCacheElement getNextPrimary(final int fromIndex) {
109 final int numIcons = favicons.size();
111 int searchIndex = fromIndex;
112 while (searchIndex < numIcons) {
113 FaviconCacheElement element = favicons.get(searchIndex);
115 if (element.isPrimary) {
116 if (element.invalidated) {
117 // We return null here, despite the possible existence of other primaries,
118 // because we know the most suitable primary for this request exists, but is
119 // no longer in the cache. By returning null, we cause the caller to load the
120 // missing primary from the database and call again.
121 return null;
122 }
123 return element;
124 }
125 searchIndex++;
126 }
128 // No larger primary available. Let's look for smaller ones...
129 searchIndex = fromIndex - 1;
130 while (searchIndex >= 0) {
131 FaviconCacheElement element = favicons.get(searchIndex);
133 if (element.isPrimary) {
134 if (element.invalidated) {
135 return null;
136 }
137 return element;
138 }
139 searchIndex--;
140 }
142 Log.e(LOGTAG, "No primaries found in Favicon cache structure. This is madness!");
144 return null;
145 }
147 /**
148 * Ensure the dominant colour field is populated for this favicon.
149 */
150 public int ensureDominantColor() {
151 if (dominantColor == -1) {
152 // Find a payload, any payload, that is not invalidated.
153 for (FaviconCacheElement element : favicons) {
154 if (!element.invalidated) {
155 dominantColor = BitmapUtils.getDominantColor(element.faviconPayload);
156 return dominantColor;
157 }
158 }
159 dominantColor = 0xFFFFFF;
160 }
162 return dominantColor;
163 }
164 }