Bug 926430 - Part 5: fetch catched favicons on the UI thread. r=bnicholson

This commit is contained in:
Richard Newman 2013-10-31 10:35:17 -07:00
parent e6b1f35a2c
commit 150e5526f9
3 changed files with 86 additions and 48 deletions

View File

@ -37,9 +37,10 @@ public class Favicons {
// Number of URL mappings from page URL to Favicon URL to cache in memory.
public static final int PAGE_URL_MAPPINGS_TO_STORE = 128;
public static final int NOT_LOADING = 0;
public static final int FLAG_PERSIST = 1;
public static final int FLAG_SCALE = 2;
public static final int NOT_LOADING = 0;
public static final int LOADED = 1;
public static final int FLAG_PERSIST = 2;
public static final int FLAG_SCALE = 4;
protected static Context sContext;
@ -68,17 +69,31 @@ public class Favicons {
}
private static FaviconCache sFaviconsCache;
static void dispatchResult(final String pageUrl, final String faviconURL, final Bitmap image,
/**
* 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) {
// We want to always run the listener on UI thread
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() {
if (listener != null) {
listener.onFaviconLoaded(pageUrl, faviconURL, image);
}
listener.onFaviconLoaded(pageUrl, faviconURL, image);
}
});
return NOT_LOADING;
}
/**
@ -93,7 +108,8 @@ public class Favicons {
* @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.
* @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 getFaviconForSize(String pageURL, String faviconURL, int targetSize, int flags, OnFaviconLoadedListener listener) {
// If there's no favicon URL given, try and hit the cache with the default one.
@ -104,20 +120,17 @@ public class Favicons {
// If it's something we can't even figure out a default URL for, just give up.
if (cacheURL == null) {
dispatchResult(pageURL, null, sDefaultFavicon, listener);
return NOT_LOADING;
return dispatchResult(pageURL, null, sDefaultFavicon, listener);
}
Bitmap cachedIcon = getSizedFaviconFromCache(cacheURL, targetSize);
if (cachedIcon != null) {
dispatchResult(pageURL, cacheURL, cachedIcon, listener);
return NOT_LOADING;
return dispatchResult(pageURL, cacheURL, cachedIcon, listener);
}
// Check if favicon has failed.
if (sFaviconsCache.isFailedFavicon(cacheURL)) {
dispatchResult(pageURL, cacheURL, sDefaultFavicon, listener);
return NOT_LOADING;
return dispatchResult(pageURL, cacheURL, sDefaultFavicon, listener);
}
// Failing that, try and get one from the database or internet.
@ -159,16 +172,14 @@ public class Favicons {
if (targetURL != null) {
// Check if favicon has failed.
if (sFaviconsCache.isFailedFavicon(targetURL)) {
dispatchResult(pageURL, targetURL, null, callback);
return NOT_LOADING;
return dispatchResult(pageURL, targetURL, null, callback);
}
// Do we have a Favicon in the cache for this favicon URL?
Bitmap result = getSizedFaviconFromCache(targetURL, targetSize);
if (result != null) {
// Victory - immediate response!
dispatchResult(pageURL, targetURL, result, callback);
return NOT_LOADING;
return dispatchResult(pageURL, targetURL, result, callback);
}
}

View File

@ -132,6 +132,16 @@ public class TopSitesGridItemView extends RelativeLayout {
mTitleView.setCompoundDrawablesWithIntrinsicBounds(pinned ? R.drawable.pin : 0, 0, 0, 0);
}
public void blankOut() {
mUrl = "";
mTitle = "";
mIsPinned = false;
updateTitleView();
mTitleView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
setLoadId(Favicons.NOT_LOADING);
displayThumbnail(R.drawable.top_site_add);
}
/**
* Updates the title, URL, and pinned state of this view.
*
@ -139,7 +149,7 @@ public class TopSitesGridItemView extends RelativeLayout {
*
* Returns true if any fields changed.
*/
public boolean updateState(final String title, final String url, final boolean pinned) {
public boolean updateState(final String title, final String url, final boolean pinned, final Bitmap thumbnail) {
boolean changed = false;
if (mUrl == null || !mUrl.equals(url)) {
mUrl = url;
@ -151,6 +161,14 @@ public class TopSitesGridItemView extends RelativeLayout {
changed = true;
}
if (thumbnail != null) {
displayThumbnail(thumbnail);
} else if (changed) {
// Because we'll have a new favicon or thumbnail arriving shortly, and
// we need to not reject it because we already had a thumbnail.
mThumbnail = null;
}
if (changed) {
updateTitleView();
setLoadId(Favicons.NOT_LOADING);

View File

@ -559,37 +559,46 @@ public class TopSitesPage extends HomeFragment {
final TopSitesGridItemView view = (TopSitesGridItemView) bindView;
// Debounce bindView calls to avoid redundant redraws and favicon
// fetches.
final boolean updated = view.updateState(title, url, pinned);
// If there is no url, then show "add bookmark".
if (TextUtils.isEmpty(url)) {
view.displayThumbnail(R.drawable.top_site_add);
} else {
// Show the thumbnail, if any.
Bitmap thumbnail = (mThumbnails != null ? mThumbnails.get(url) : null);
if (thumbnail != null) {
view.displayThumbnail(thumbnail);
return;
}
// Thumbnails are delivered late, so we can't short-circuit any
// sooner than this. But we can avoid a duplicate favicon
// fetch...
if (!updated) {
Log.d(LOGTAG, "bindView called twice for same values; short-circuiting.");
return;
}
// If we have no thumbnail, attempt to show a Favicon instead.
LoadIDAwareFaviconLoadedListener listener = new LoadIDAwareFaviconLoadedListener(view);
final int loadId = Favicons.getSizedFaviconForPageFromLocal(url, listener);
// Give each side enough information to shake hands later.
listener.setLoadId(loadId);
view.setLoadId(loadId);
view.blankOut();
return;
}
// Show the thumbnail, if any.
Bitmap thumbnail = (mThumbnails != null ? mThumbnails.get(url) : null);
// Debounce bindView calls to avoid redundant redraws and favicon
// fetches.
final boolean updated = view.updateState(title, url, pinned, thumbnail);
// If we sent in a thumbnail, we're done now.
if (thumbnail != null) {
return;
}
// Thumbnails are delivered late, so we can't short-circuit any
// sooner than this. But we can avoid a duplicate favicon
// fetch...
if (!updated) {
Log.d(LOGTAG, "bindView called twice for same values; short-circuiting.");
return;
}
// If we have no thumbnail, attempt to show a Favicon instead.
LoadIDAwareFaviconLoadedListener listener = new LoadIDAwareFaviconLoadedListener(view);
final int loadId = Favicons.getSizedFaviconForPageFromLocal(url, listener);
if (loadId == Favicons.LOADED) {
// Great!
return;
}
// Otherwise, do this until the async lookup returns.
view.displayThumbnail(R.drawable.favicon);
// Give each side enough information to shake hands later.
listener.setLoadId(loadId);
view.setLoadId(loadId);
}
@Override