|
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/. */ |
|
4 |
|
5 package org.mozilla.gecko.favicons.cache; |
|
6 |
|
7 import android.graphics.Bitmap; |
|
8 import android.util.Log; |
|
9 import org.mozilla.gecko.gfx.BitmapUtils; |
|
10 |
|
11 import java.util.ArrayList; |
|
12 import java.util.Collections; |
|
13 |
|
14 public class FaviconsForURL { |
|
15 private static final String LOGTAG = "FaviconForURL"; |
|
16 |
|
17 private volatile int dominantColor = -1; |
|
18 |
|
19 final long downloadTimestamp; |
|
20 final ArrayList<FaviconCacheElement> favicons; |
|
21 |
|
22 public final boolean hasFailed; |
|
23 |
|
24 public FaviconsForURL(int size) { |
|
25 this(size, false); |
|
26 } |
|
27 |
|
28 public FaviconsForURL(int size, boolean failed) { |
|
29 hasFailed = failed; |
|
30 downloadTimestamp = System.currentTimeMillis(); |
|
31 favicons = new ArrayList<FaviconCacheElement>(size); |
|
32 } |
|
33 |
|
34 public FaviconCacheElement addSecondary(Bitmap favicon, int imageSize) { |
|
35 return addInternal(favicon, false, imageSize); |
|
36 } |
|
37 |
|
38 public FaviconCacheElement addPrimary(Bitmap favicon) { |
|
39 return addInternal(favicon, true, favicon.getWidth()); |
|
40 } |
|
41 |
|
42 private FaviconCacheElement addInternal(Bitmap favicon, boolean isPrimary, int imageSize) { |
|
43 FaviconCacheElement c = new FaviconCacheElement(favicon, isPrimary, imageSize, this); |
|
44 |
|
45 int index = Collections.binarySearch(favicons, c); |
|
46 |
|
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 } |
|
52 |
|
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); |
|
58 |
|
59 return c; |
|
60 } |
|
61 |
|
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); |
|
72 |
|
73 int index = Collections.binarySearch(favicons, dummy); |
|
74 |
|
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 } |
|
82 |
|
83 // index is now 'x', as described above. |
|
84 |
|
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 } |
|
92 |
|
93 return index; |
|
94 } |
|
95 |
|
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(); |
|
110 |
|
111 int searchIndex = fromIndex; |
|
112 while (searchIndex < numIcons) { |
|
113 FaviconCacheElement element = favicons.get(searchIndex); |
|
114 |
|
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 } |
|
127 |
|
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); |
|
132 |
|
133 if (element.isPrimary) { |
|
134 if (element.invalidated) { |
|
135 return null; |
|
136 } |
|
137 return element; |
|
138 } |
|
139 searchIndex--; |
|
140 } |
|
141 |
|
142 Log.e(LOGTAG, "No primaries found in Favicon cache structure. This is madness!"); |
|
143 |
|
144 return null; |
|
145 } |
|
146 |
|
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 } |
|
161 |
|
162 return dominantColor; |
|
163 } |
|
164 } |