Decode JPEG on background thread
Bug:6202229
Change-Id: I5cb52943ed8db6b22cd5fe784f692ab00ab323ae
diff --git a/src/com/android/contacts/ContactPhotoManager.java b/src/com/android/contacts/ContactPhotoManager.java
index 8688426..4286293 100644
--- a/src/com/android/contacts/ContactPhotoManager.java
+++ b/src/com/android/contacts/ContactPhotoManager.java
@@ -537,7 +537,7 @@
private boolean loadCachedPhoto(ImageView view, Request request, boolean fadeIn) {
BitmapHolder holder = mBitmapHolderCache.get(request.getKey());
if (holder == null) {
- // The bitmap has not been loaded - should display the placeholder image.
+ // The bitmap has not been loaded ==> show default avatar
request.applyDefaultImage(view);
return false;
}
@@ -547,13 +547,19 @@
return holder.fresh;
}
- // Optionally decode bytes into a bitmap
- final long inflateStart = System.currentTimeMillis();
- final boolean decodingPicture = holder.bitmap == null;
- inflateBitmap(holder, request.getRequestedExtent());
- if (decodingPicture && DEBUG) {
- Log.d(TAG, "Inflated a picture on the foreground thread. Took " +
- (System.currentTimeMillis() - inflateStart) + "ms");
+ Bitmap cachedBitmap = holder.bitmapRef == null ? null : holder.bitmapRef.get();
+ if (cachedBitmap == null) {
+ if (holder.bytes.length < 8 * 1024) {
+ // Small thumbnails are usually quick to inflate. Let's do that on the UI thread
+ inflateBitmap(holder, request.getRequestedExtent());
+ cachedBitmap = holder.bitmap;
+ if (cachedBitmap == null) return false;
+ } else {
+ // This is bigger data. Let's send that back to the Loader so that we can
+ // inflate this in the background
+ request.applyDefaultImage(view);
+ return false;
+ }
}
final Drawable previousDrawable = view.getDrawable();
@@ -561,24 +567,23 @@
final Drawable[] layers = new Drawable[2];
// Prevent cascade of TransitionDrawables.
if (previousDrawable instanceof TransitionDrawable) {
- final TransitionDrawable transitionDrawable = (TransitionDrawable) previousDrawable;
- layers[0] =
- transitionDrawable.getDrawable(transitionDrawable.getNumberOfLayers() - 1);
+ final TransitionDrawable previousTransitionDrawable =
+ (TransitionDrawable) previousDrawable;
+ layers[0] = previousTransitionDrawable.getDrawable(
+ previousTransitionDrawable.getNumberOfLayers() - 1);
} else {
layers[0] = previousDrawable;
}
- layers[1] = new BitmapDrawable(mContext.getResources(), holder.bitmap);
+ layers[1] = new BitmapDrawable(mContext.getResources(), cachedBitmap);
TransitionDrawable drawable = new TransitionDrawable(layers);
view.setImageDrawable(drawable);
drawable.startTransition(FADE_TRANSITION_DURATION);
} else {
- view.setImageBitmap(holder.bitmap);
+ view.setImageBitmap(cachedBitmap);
}
- if (holder.bitmap != null) {
- // Put the bitmap in the LRU cache
- mBitmapCache.put(request.getKey(), holder.bitmap);
- }
+ // Put the bitmap in the LRU cache
+ mBitmapCache.put(request.getKey(), cachedBitmap);
// Soften the reference
holder.bitmap = null;
@@ -778,13 +783,15 @@
// requested
Request request = Request.createFromUri(photoUri, smallerExtent, false, DEFAULT_AVATAR);
BitmapHolder holder = new BitmapHolder(photoBytes, smallerExtent);
+ holder.bitmapRef = new SoftReference<Bitmap>(bitmap);
mBitmapHolderCache.put(request.getKey(), holder);
mBitmapHolderCacheAllUnfresh = false;
mBitmapCache.put(request.getKey(), bitmap);
}
/**
- * Populates an array of photo IDs that need to be loaded.
+ * Populates an array of photo IDs that need to be loaded. Also decodes bitmaps that we have
+ * already loaded
*/
private void obtainPhotoIdsAndUrisToLoad(Set<Long> photoIds,
Set<String> photoIdsAsStrings, Set<Request> uris) {
@@ -792,6 +799,8 @@
photoIdsAsStrings.clear();
uris.clear();
+ boolean jpegsDecoded = false;
+
/*
* Since the call is made from the loader thread, the map could be
* changing during the iteration. That's not really a problem:
@@ -803,16 +812,25 @@
Iterator<Request> iterator = mPendingRequests.values().iterator();
while (iterator.hasNext()) {
Request request = iterator.next();
- BitmapHolder holder = mBitmapHolderCache.get(request);
- if (holder == null || !holder.fresh) {
- if (request.isUriRequest()) {
- uris.add(request);
- } else {
- photoIds.add(request.getId());
- photoIdsAsStrings.add(String.valueOf(request.mId));
+ final BitmapHolder holder = mBitmapHolderCache.get(request.getKey());
+ if (holder != null && holder.bytes != null && holder.fresh &&
+ (holder.bitmapRef == null || holder.bitmapRef.get() == null)) {
+ // This was previously loaded but we don't currently have the inflated Bitmap
+ inflateBitmap(holder, request.getRequestedExtent());
+ jpegsDecoded = true;
+ } else {
+ if (holder == null || !holder.fresh) {
+ if (request.isUriRequest()) {
+ uris.add(request);
+ } else {
+ photoIds.add(request.getId());
+ photoIdsAsStrings.add(String.valueOf(request.mId));
+ }
}
}
}
+
+ if (jpegsDecoded) mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
}
/**