mobile/android/base/favicons/Favicons.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko.favicons;
michael@0 7
michael@0 8 import org.mozilla.gecko.AboutPages;
michael@0 9 import org.mozilla.gecko.AppConstants;
michael@0 10 import org.mozilla.gecko.GeckoAppShell;
michael@0 11 import org.mozilla.gecko.R;
michael@0 12 import org.mozilla.gecko.Tab;
michael@0 13 import org.mozilla.gecko.Tabs;
michael@0 14 import org.mozilla.gecko.db.BrowserDB;
michael@0 15 import org.mozilla.gecko.favicons.cache.FaviconCache;
michael@0 16 import org.mozilla.gecko.util.GeckoJarReader;
michael@0 17 import org.mozilla.gecko.util.NonEvictingLruCache;
michael@0 18 import org.mozilla.gecko.util.ThreadUtils;
michael@0 19
michael@0 20 import android.content.Context;
michael@0 21 import android.content.res.Resources;
michael@0 22 import android.graphics.Bitmap;
michael@0 23 import android.graphics.BitmapFactory;
michael@0 24 import android.text.TextUtils;
michael@0 25 import android.util.Log;
michael@0 26 import android.util.SparseArray;
michael@0 27
michael@0 28 import java.io.File;
michael@0 29 import java.net.URI;
michael@0 30 import java.net.URISyntaxException;
michael@0 31 import java.util.Arrays;
michael@0 32 import java.util.Iterator;
michael@0 33 import java.util.List;
michael@0 34
michael@0 35 public class Favicons {
michael@0 36 private static final String LOGTAG = "GeckoFavicons";
michael@0 37
michael@0 38 // A magic URL representing the app's own favicon, used for about: pages.
michael@0 39 private static final String BUILT_IN_FAVICON_URL = "about:favicon";
michael@0 40
michael@0 41 // Size of the favicon bitmap cache, in bytes (Counting payload only).
michael@0 42 public static final int FAVICON_CACHE_SIZE_BYTES = 512 * 1024;
michael@0 43
michael@0 44 // Number of URL mappings from page URL to Favicon URL to cache in memory.
michael@0 45 public static final int NUM_PAGE_URL_MAPPINGS_TO_STORE = 128;
michael@0 46
michael@0 47 public static final int NOT_LOADING = 0;
michael@0 48 public static final int LOADED = 1;
michael@0 49 public static final int FLAG_PERSIST = 2;
michael@0 50 public static final int FLAG_SCALE = 4;
michael@0 51
michael@0 52 protected static Context context;
michael@0 53
michael@0 54 // The default Favicon to show if no other can be found.
michael@0 55 public static Bitmap defaultFavicon;
michael@0 56
michael@0 57 // The density-adjusted default Favicon dimensions.
michael@0 58 public static int defaultFaviconSize;
michael@0 59
michael@0 60 // The density-adjusted maximum Favicon dimensions.
michael@0 61 public static int largestFaviconSize;
michael@0 62
michael@0 63 private static final SparseArray<LoadFaviconTask> loadTasks = new SparseArray<LoadFaviconTask>();
michael@0 64
michael@0 65 // Cache to hold mappings between page URLs and Favicon URLs. Used to avoid going to the DB when
michael@0 66 // doing so is not necessary.
michael@0 67 private static final NonEvictingLruCache<String, String> pageURLMappings = new NonEvictingLruCache<String, String>(NUM_PAGE_URL_MAPPINGS_TO_STORE);
michael@0 68
michael@0 69 public static String getFaviconURLForPageURLFromCache(String pageURL) {
michael@0 70 return pageURLMappings.get(pageURL);
michael@0 71 }
michael@0 72
michael@0 73 /**
michael@0 74 * Insert the given pageUrl->faviconUrl mapping into the memory cache of such mappings.
michael@0 75 * Useful for short-circuiting local database access.
michael@0 76 */
michael@0 77 public static void putFaviconURLForPageURLInCache(String pageURL, String faviconURL) {
michael@0 78 pageURLMappings.put(pageURL, faviconURL);
michael@0 79 }
michael@0 80
michael@0 81 private static FaviconCache faviconsCache;
michael@0 82
michael@0 83 /**
michael@0 84 * Returns either NOT_LOADING, or LOADED if the onFaviconLoaded call could
michael@0 85 * be made on the main thread.
michael@0 86 * If no listener is provided, NOT_LOADING is returned.
michael@0 87 */
michael@0 88 static int dispatchResult(final String pageUrl, final String faviconURL, final Bitmap image,
michael@0 89 final OnFaviconLoadedListener listener) {
michael@0 90 if (listener == null) {
michael@0 91 return NOT_LOADING;
michael@0 92 }
michael@0 93
michael@0 94 if (ThreadUtils.isOnUiThread()) {
michael@0 95 listener.onFaviconLoaded(pageUrl, faviconURL, image);
michael@0 96 return LOADED;
michael@0 97 }
michael@0 98
michael@0 99 // We want to always run the listener on UI thread.
michael@0 100 ThreadUtils.postToUiThread(new Runnable() {
michael@0 101 @Override
michael@0 102 public void run() {
michael@0 103 listener.onFaviconLoaded(pageUrl, faviconURL, image);
michael@0 104 }
michael@0 105 });
michael@0 106 return NOT_LOADING;
michael@0 107 }
michael@0 108
michael@0 109 /**
michael@0 110 * Only returns a non-null Bitmap if the entire path is cached -- the
michael@0 111 * page URL to favicon URL, and the favicon URL to in-memory bitmaps.
michael@0 112 *
michael@0 113 * Returns null otherwise.
michael@0 114 */
michael@0 115 public static Bitmap getSizedFaviconForPageFromCache(final String pageURL, int targetSize) {
michael@0 116 final String faviconURL = pageURLMappings.get(pageURL);
michael@0 117 if (faviconURL == null) {
michael@0 118 return null;
michael@0 119 }
michael@0 120 return getSizedFaviconFromCache(faviconURL, targetSize);
michael@0 121 }
michael@0 122
michael@0 123 /**
michael@0 124 * Get a Favicon as close as possible to the target dimensions for the URL provided.
michael@0 125 * If a result is instantly available from the cache, it is returned and the listener is invoked.
michael@0 126 * Otherwise, the result is drawn from the database or network and the listener invoked when the
michael@0 127 * result becomes available.
michael@0 128 *
michael@0 129 * @param pageURL Page URL for which a Favicon is desired.
michael@0 130 * @param faviconURL URL of the Favicon to be downloaded, if known. If none provided, an educated
michael@0 131 * guess is made by the system.
michael@0 132 * @param targetSize Target size of the returned Favicon
michael@0 133 * @param listener Listener to call with the result of the load operation, if the result is not
michael@0 134 * immediately available.
michael@0 135 * @return The id of the asynchronous task created, NOT_LOADING if none is created, or
michael@0 136 * LOADED if the value could be dispatched on the current thread.
michael@0 137 */
michael@0 138 public static int getSizedFavicon(String pageURL, String faviconURL, int targetSize, int flags, OnFaviconLoadedListener listener) {
michael@0 139 // Do we know the favicon URL for this page already?
michael@0 140 String cacheURL = faviconURL;
michael@0 141 if (cacheURL == null) {
michael@0 142 cacheURL = pageURLMappings.get(pageURL);
michael@0 143 }
michael@0 144
michael@0 145 // If there's no favicon URL given, try and hit the cache with the default one.
michael@0 146 if (cacheURL == null) {
michael@0 147 cacheURL = guessDefaultFaviconURL(pageURL);
michael@0 148 }
michael@0 149
michael@0 150 // If it's something we can't even figure out a default URL for, just give up.
michael@0 151 if (cacheURL == null) {
michael@0 152 return dispatchResult(pageURL, null, defaultFavicon, listener);
michael@0 153 }
michael@0 154
michael@0 155 Bitmap cachedIcon = getSizedFaviconFromCache(cacheURL, targetSize);
michael@0 156 if (cachedIcon != null) {
michael@0 157 return dispatchResult(pageURL, cacheURL, cachedIcon, listener);
michael@0 158 }
michael@0 159
michael@0 160 // Check if favicon has failed.
michael@0 161 if (faviconsCache.isFailedFavicon(cacheURL)) {
michael@0 162 return dispatchResult(pageURL, cacheURL, defaultFavicon, listener);
michael@0 163 }
michael@0 164
michael@0 165 // Failing that, try and get one from the database or internet.
michael@0 166 return loadUncachedFavicon(pageURL, faviconURL, flags, targetSize, listener);
michael@0 167 }
michael@0 168
michael@0 169 /**
michael@0 170 * Returns the cached Favicon closest to the target size if any exists or is coercible. Returns
michael@0 171 * null otherwise. Does not query the database or network for the Favicon is the result is not
michael@0 172 * immediately available.
michael@0 173 *
michael@0 174 * @param faviconURL URL of the Favicon to query for.
michael@0 175 * @param targetSize The desired size of the returned Favicon.
michael@0 176 * @return The cached Favicon, rescaled to be as close as possible to the target size, if any exists.
michael@0 177 * null if no applicable Favicon exists in the cache.
michael@0 178 */
michael@0 179 public static Bitmap getSizedFaviconFromCache(String faviconURL, int targetSize) {
michael@0 180 return faviconsCache.getFaviconForDimensions(faviconURL, targetSize);
michael@0 181 }
michael@0 182
michael@0 183 /**
michael@0 184 * Attempts to find a Favicon for the provided page URL from either the mem cache or the database.
michael@0 185 * Does not need an explicit favicon URL, since, as we are accessing the database anyway, we
michael@0 186 * can query the history DB for the Favicon URL.
michael@0 187 * Handy for easing the transition from caching with page URLs to caching with Favicon URLs.
michael@0 188 *
michael@0 189 * A null result is passed to the listener if no value is locally available. The Favicon is not
michael@0 190 * added to the failure cache.
michael@0 191 *
michael@0 192 * @param pageURL Page URL for which a Favicon is wanted.
michael@0 193 * @param targetSize Target size of the desired Favicon to pass to the cache query
michael@0 194 * @param callback Callback to fire with the result.
michael@0 195 * @return The job ID of the spawned async task, if any.
michael@0 196 */
michael@0 197 public static int getSizedFaviconForPageFromLocal(final String pageURL, final int targetSize, final OnFaviconLoadedListener callback) {
michael@0 198 // Firstly, try extremely hard to cheat.
michael@0 199 // Have we cached this favicon URL? If we did, we can consult the memcache right away.
michael@0 200 String targetURL = pageURLMappings.get(pageURL);
michael@0 201 if (targetURL != null) {
michael@0 202 // Check if favicon has failed.
michael@0 203 if (faviconsCache.isFailedFavicon(targetURL)) {
michael@0 204 return dispatchResult(pageURL, targetURL, null, callback);
michael@0 205 }
michael@0 206
michael@0 207 // Do we have a Favicon in the cache for this favicon URL?
michael@0 208 Bitmap result = getSizedFaviconFromCache(targetURL, targetSize);
michael@0 209 if (result != null) {
michael@0 210 // Victory - immediate response!
michael@0 211 return dispatchResult(pageURL, targetURL, result, callback);
michael@0 212 }
michael@0 213 }
michael@0 214
michael@0 215 // No joy using in-memory resources. Go to background thread and ask the database.
michael@0 216 LoadFaviconTask task = new LoadFaviconTask(ThreadUtils.getBackgroundHandler(), pageURL, targetURL, 0, callback, targetSize, true);
michael@0 217 int taskId = task.getId();
michael@0 218 synchronized(loadTasks) {
michael@0 219 loadTasks.put(taskId, task);
michael@0 220 }
michael@0 221 task.execute();
michael@0 222 return taskId;
michael@0 223 }
michael@0 224
michael@0 225 public static int getSizedFaviconForPageFromLocal(final String pageURL, final OnFaviconLoadedListener callback) {
michael@0 226 return getSizedFaviconForPageFromLocal(pageURL, defaultFaviconSize, callback);
michael@0 227 }
michael@0 228
michael@0 229 /**
michael@0 230 * Helper method to determine the URL of the Favicon image for a given page URL by querying the
michael@0 231 * history database. Should only be called from the background thread - does database access.
michael@0 232 *
michael@0 233 * @param pageURL The URL of a webpage with a Favicon.
michael@0 234 * @return The URL of the Favicon used by that webpage, according to either the History database
michael@0 235 * or a somewhat educated guess.
michael@0 236 */
michael@0 237 public static String getFaviconURLForPageURL(String pageURL) {
michael@0 238 // Attempt to determine the Favicon URL from the Tabs datastructure. Can dodge having to use
michael@0 239 // the database sometimes by doing this.
michael@0 240 String targetURL;
michael@0 241 Tab theTab = Tabs.getInstance().getFirstTabForUrl(pageURL);
michael@0 242 if (theTab != null) {
michael@0 243 targetURL = theTab.getFaviconURL();
michael@0 244 if (targetURL != null) {
michael@0 245 return targetURL;
michael@0 246 }
michael@0 247 }
michael@0 248
michael@0 249 targetURL = BrowserDB.getFaviconUrlForHistoryUrl(context.getContentResolver(), pageURL);
michael@0 250 if (targetURL == null) {
michael@0 251 // Nothing in the history database. Fall back to the default URL and hope for the best.
michael@0 252 targetURL = guessDefaultFaviconURL(pageURL);
michael@0 253 }
michael@0 254 return targetURL;
michael@0 255 }
michael@0 256
michael@0 257 /**
michael@0 258 * Helper function to create an async job to load a Favicon which does not exist in the memcache.
michael@0 259 * Contains logic to prevent the repeated loading of Favicons which have previously failed.
michael@0 260 * There is no support for recovery from transient failures.
michael@0 261 *
michael@0 262 * @param pageUrl URL of the page for which to load a Favicon. If null, no job is created.
michael@0 263 * @param faviconUrl The URL of the Favicon to load. If null, an attempt to infer the value from
michael@0 264 * the history database will be made, and ultimately an attempt to guess will
michael@0 265 * be made.
michael@0 266 * @param flags Flags to be used by the LoadFaviconTask while loading. Currently only one flag
michael@0 267 * is supported, LoadFaviconTask.FLAG_PERSIST.
michael@0 268 * If FLAG_PERSIST is set and the Favicon is ultimately loaded from the internet,
michael@0 269 * the downloaded Favicon is subsequently stored in the local database.
michael@0 270 * If FLAG_PERSIST is unset, the downloaded Favicon is stored only in the memcache.
michael@0 271 * FLAG_PERSIST has no effect on loads which come from the database.
michael@0 272 * @param listener The OnFaviconLoadedListener to invoke with the result of this Favicon load.
michael@0 273 * @return The id of the LoadFaviconTask handling this job.
michael@0 274 */
michael@0 275 private static int loadUncachedFavicon(String pageUrl, String faviconUrl, int flags, int targetSize, OnFaviconLoadedListener listener) {
michael@0 276 // Handle the case where we have no page url.
michael@0 277 if (TextUtils.isEmpty(pageUrl)) {
michael@0 278 dispatchResult(null, null, null, listener);
michael@0 279 return NOT_LOADING;
michael@0 280 }
michael@0 281
michael@0 282 LoadFaviconTask task = new LoadFaviconTask(ThreadUtils.getBackgroundHandler(), pageUrl, faviconUrl, flags, listener, targetSize, false);
michael@0 283
michael@0 284 int taskId = task.getId();
michael@0 285 synchronized(loadTasks) {
michael@0 286 loadTasks.put(taskId, task);
michael@0 287 }
michael@0 288
michael@0 289 task.execute();
michael@0 290
michael@0 291 return taskId;
michael@0 292 }
michael@0 293
michael@0 294 public static void putFaviconInMemCache(String pageUrl, Bitmap image) {
michael@0 295 faviconsCache.putSingleFavicon(pageUrl, image);
michael@0 296 }
michael@0 297
michael@0 298 /**
michael@0 299 * Adds the bitmaps given by the specified iterator to the cache associated with the url given.
michael@0 300 * Future requests for images will be able to select the least larger image than the target
michael@0 301 * size from this new set of images.
michael@0 302 *
michael@0 303 * @param pageUrl The URL to associate the new favicons with.
michael@0 304 * @param images An iterator over the new favicons to put in the cache.
michael@0 305 */
michael@0 306 public static void putFaviconsInMemCache(String pageUrl, Iterator<Bitmap> images, boolean permanently) {
michael@0 307 faviconsCache.putFavicons(pageUrl, images, permanently);
michael@0 308 }
michael@0 309
michael@0 310 public static void putFaviconsInMemCache(String pageUrl, Iterator<Bitmap> images) {
michael@0 311 putFaviconsInMemCache(pageUrl, images, false);
michael@0 312 }
michael@0 313
michael@0 314 public static void clearMemCache() {
michael@0 315 faviconsCache.evictAll();
michael@0 316 pageURLMappings.evictAll();
michael@0 317 }
michael@0 318
michael@0 319 public static void putFaviconInFailedCache(String faviconURL) {
michael@0 320 faviconsCache.putFailed(faviconURL);
michael@0 321 }
michael@0 322
michael@0 323 public static boolean cancelFaviconLoad(int taskId) {
michael@0 324 if (taskId == NOT_LOADING) {
michael@0 325 return false;
michael@0 326 }
michael@0 327
michael@0 328 boolean cancelled;
michael@0 329 synchronized (loadTasks) {
michael@0 330 if (loadTasks.indexOfKey(taskId) < 0) {
michael@0 331 return false;
michael@0 332 }
michael@0 333
michael@0 334 Log.v(LOGTAG, "Cancelling favicon load " + taskId + ".");
michael@0 335
michael@0 336 LoadFaviconTask task = loadTasks.get(taskId);
michael@0 337 cancelled = task.cancel(false);
michael@0 338 }
michael@0 339 return cancelled;
michael@0 340 }
michael@0 341
michael@0 342 public static void close() {
michael@0 343 Log.d(LOGTAG, "Closing Favicons database");
michael@0 344
michael@0 345 // Cancel any pending tasks
michael@0 346 synchronized (loadTasks) {
michael@0 347 final int count = loadTasks.size();
michael@0 348 for (int i = 0; i < count; i++) {
michael@0 349 cancelFaviconLoad(loadTasks.keyAt(i));
michael@0 350 }
michael@0 351 loadTasks.clear();
michael@0 352 }
michael@0 353
michael@0 354 LoadFaviconTask.closeHTTPClient();
michael@0 355 }
michael@0 356
michael@0 357 /**
michael@0 358 * Get the dominant colour of the Favicon at the URL given, if any exists in the cache.
michael@0 359 *
michael@0 360 * @param url The URL of the Favicon, to be used as the cache key for the colour value.
michael@0 361 * @return The dominant colour of the provided Favicon.
michael@0 362 */
michael@0 363 public static int getFaviconColor(String url) {
michael@0 364 return faviconsCache.getDominantColor(url);
michael@0 365 }
michael@0 366
michael@0 367 /**
michael@0 368 * Called by GeckoApp on startup to pass this class a reference to the GeckoApp object used as
michael@0 369 * the application's Context.
michael@0 370 * Consider replacing with references to a staticly held reference to the GeckoApp object.
michael@0 371 *
michael@0 372 * @param context A reference to the GeckoApp instance.
michael@0 373 */
michael@0 374 public static void attachToContext(Context context) throws Exception {
michael@0 375 final Resources res = context.getResources();
michael@0 376 Favicons.context = context;
michael@0 377
michael@0 378 // Decode the default Favicon ready for use.
michael@0 379 defaultFavicon = BitmapFactory.decodeResource(res, R.drawable.favicon);
michael@0 380 if (defaultFavicon == null) {
michael@0 381 throw new Exception("Null default favicon was returned from the resources system!");
michael@0 382 }
michael@0 383
michael@0 384 defaultFaviconSize = res.getDimensionPixelSize(R.dimen.favicon_bg);
michael@0 385
michael@0 386 // Screen-density-adjusted upper limit on favicon size. Favicons larger than this are
michael@0 387 // downscaled to this size or discarded.
michael@0 388 largestFaviconSize = context.getResources().getDimensionPixelSize(R.dimen.favicon_largest_interesting_size);
michael@0 389 faviconsCache = new FaviconCache(FAVICON_CACHE_SIZE_BYTES, largestFaviconSize);
michael@0 390
michael@0 391 // Initialize page mappings for each of our special pages.
michael@0 392 for (String url : AboutPages.getDefaultIconPages()) {
michael@0 393 pageURLMappings.putWithoutEviction(url, BUILT_IN_FAVICON_URL);
michael@0 394 }
michael@0 395
michael@0 396 // Load and cache the built-in favicon in each of its sizes.
michael@0 397 // TODO: don't open the zip twice!
michael@0 398 List<Bitmap> toInsert = Arrays.asList(loadBrandingBitmap(context, "favicon64.png"),
michael@0 399 loadBrandingBitmap(context, "favicon32.png"));
michael@0 400
michael@0 401 putFaviconsInMemCache(BUILT_IN_FAVICON_URL, toInsert.iterator(), true);
michael@0 402 }
michael@0 403
michael@0 404 /**
michael@0 405 * Compute a string like:
michael@0 406 * "jar:jar:file:///data/app/org.mozilla.firefox-1.apk!/assets/omni.ja!/chrome/chrome/content/branding/favicon64.png"
michael@0 407 */
michael@0 408 private static String getBrandingBitmapPath(Context context, String name) {
michael@0 409 final String apkPath = context.getPackageResourcePath();
michael@0 410 return "jar:jar:" + new File(apkPath).toURI() + "!/" +
michael@0 411 AppConstants.OMNIJAR_NAME + "!/" +
michael@0 412 "chrome/chrome/content/branding/" + name;
michael@0 413 }
michael@0 414
michael@0 415 private static Bitmap loadBrandingBitmap(Context context, String name) {
michael@0 416 Bitmap b = GeckoJarReader.getBitmap(context.getResources(),
michael@0 417 getBrandingBitmapPath(context, name));
michael@0 418 if (b == null) {
michael@0 419 throw new IllegalStateException("Bitmap " + name + " missing from JAR!");
michael@0 420 }
michael@0 421 return b;
michael@0 422 }
michael@0 423
michael@0 424 /**
michael@0 425 * Helper method to get the default Favicon URL for a given pageURL. Generally: somewhere.com/favicon.ico
michael@0 426 *
michael@0 427 * @param pageURL Page URL for which a default Favicon URL is requested
michael@0 428 * @return The default Favicon URL.
michael@0 429 */
michael@0 430 public static String guessDefaultFaviconURL(String pageURL) {
michael@0 431 // Special-casing for about: pages. The favicon for about:pages which don't provide a link tag
michael@0 432 // is bundled in the database, keyed only by page URL, hence the need to return the page URL
michael@0 433 // here. If the database ever migrates to stop being silly in this way, this can plausibly
michael@0 434 // be removed.
michael@0 435 if (AboutPages.isAboutPage(pageURL) || pageURL.startsWith("jar:")) {
michael@0 436 return pageURL;
michael@0 437 }
michael@0 438
michael@0 439 try {
michael@0 440 // Fall back to trying "someScheme:someDomain.someExtension/favicon.ico".
michael@0 441 URI u = new URI(pageURL);
michael@0 442 return new URI(u.getScheme(),
michael@0 443 u.getAuthority(),
michael@0 444 "/favicon.ico", null,
michael@0 445 null).toString();
michael@0 446 } catch (URISyntaxException e) {
michael@0 447 Log.e(LOGTAG, "URISyntaxException getting default favicon URL", e);
michael@0 448 return null;
michael@0 449 }
michael@0 450 }
michael@0 451
michael@0 452 public static void removeLoadTask(int taskId) {
michael@0 453 synchronized(loadTasks) {
michael@0 454 loadTasks.delete(taskId);
michael@0 455 }
michael@0 456 }
michael@0 457
michael@0 458 /**
michael@0 459 * Method to wrap FaviconCache.isFailedFavicon for use by LoadFaviconTask.
michael@0 460 *
michael@0 461 * @param faviconURL Favicon URL to check for failure.
michael@0 462 */
michael@0 463 static boolean isFailedFavicon(String faviconURL) {
michael@0 464 return faviconsCache.isFailedFavicon(faviconURL);
michael@0 465 }
michael@0 466
michael@0 467 /**
michael@0 468 * Sidestep the cache and get, from either the database or the internet, a favicon
michael@0 469 * suitable for use as an app icon for the provided URL.
michael@0 470 *
michael@0 471 * Useful for creating homescreen shortcuts without being limited
michael@0 472 * by possibly low-resolution values in the cache.
michael@0 473 *
michael@0 474 * Deduces the favicon URL from the browser database, guessing if necessary.
michael@0 475 *
michael@0 476 * @param url page URL to get a large favicon image for.
michael@0 477 * @param onFaviconLoadedListener listener to call back with the result.
michael@0 478 */
michael@0 479 public static void getPreferredSizeFaviconForPage(String url, OnFaviconLoadedListener onFaviconLoadedListener) {
michael@0 480 int preferredSize = GeckoAppShell.getPreferredIconSize();
michael@0 481 loadUncachedFavicon(url, null, 0, preferredSize, onFaviconLoadedListener);
michael@0 482 }
michael@0 483 }

mercurial