Index: chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java |
index d76bd1c590f129ab676224a86e9a04d31f852eb1..9a5f17921b76db17b3261c3ade976ea6457bb049 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java |
@@ -4,6 +4,14 @@ |
package org.chromium.chrome.browser.ntp.snippets; |
+import android.content.res.Resources; |
+import android.graphics.Bitmap; |
+import android.graphics.BitmapFactory; |
+import android.graphics.drawable.BitmapDrawable; |
+import android.graphics.drawable.Drawable; |
+import android.graphics.drawable.TransitionDrawable; |
+import android.media.ThumbnailUtils; |
+import android.os.AsyncTask; |
import android.text.format.DateUtils; |
import android.view.LayoutInflater; |
import android.view.View; |
@@ -11,6 +19,8 @@ |
import android.widget.ImageView; |
import android.widget.TextView; |
+import org.chromium.base.Log; |
+import org.chromium.base.StreamUtil; |
import org.chromium.base.metrics.RecordHistogram; |
import org.chromium.base.metrics.RecordUserAction; |
import org.chromium.chrome.R; |
@@ -19,15 +29,24 @@ |
import org.chromium.chrome.browser.ntp.cards.NewTabPageListItem; |
import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder; |
+import java.io.IOException; |
+import java.io.InputStream; |
+import java.net.URL; |
+ |
/** |
* A class that represents the view for a single card snippet. |
*/ |
public class SnippetArticleViewHolder extends NewTabPageViewHolder implements View.OnClickListener { |
+ private static final String TAG = "NtpSnippets"; |
+ private static final int FADE_IN_ANIMATION_TIME_MS = 300; |
+ |
private final NewTabPageManager mNewTabPageManager; |
- public TextView mHeadlineTextView; |
- public TextView mPublisherTextView; |
- public TextView mArticleSnippetTextView; |
- public ImageView mThumbnailView; |
+ private final TextView mHeadlineTextView; |
+ private final TextView mPublisherTextView; |
+ private final TextView mArticleSnippetTextView; |
+ private final ImageView mThumbnailView; |
+ |
+ private AsyncTask<String, Void, Bitmap> mThumbnailFetchingTask; |
public String mUrl; |
public int mPosition; |
@@ -90,7 +109,72 @@ public void onBindViewHolder(NewTabPageListItem article) { |
mUrl = item.mUrl; |
mPosition = item.mPosition; |
- item.setThumbnailOnView(mThumbnailView); |
+ updateThumbnail(item); |
+ } |
+ |
+ private void updateThumbnail(final SnippetArticle snippet) { |
+ // If this view has a pending fetching task, it will display the stale thumbnail when it |
+ // finishes, so we need to cancel that task. |
+ if (mThumbnailFetchingTask != null) mThumbnailFetchingTask.cancel(true); |
+ |
+ if (snippet.getThumbnailBitmap() != null) { |
+ mThumbnailView.setImageBitmap(snippet.getThumbnailBitmap()); |
+ return; |
+ } |
+ |
+ mThumbnailView.setImageResource(R.drawable.ic_snippet_thumbnail_placeholder); |
+ |
+ if (snippet.mThumbnailUrl.isEmpty()) { |
+ Log.e(TAG, "Could not get image thumbnail due to empty URL"); |
+ return; |
+ } |
+ |
+ mThumbnailFetchingTask = new AsyncTask<String, Void, Bitmap>() { |
+ |
+ @Override |
+ protected Bitmap doInBackground(String... params) { |
+ InputStream is = null; |
+ try { |
+ is = new URL(params[0]).openStream(); |
+ return BitmapFactory.decodeStream(is); |
+ } catch (IOException e) { |
+ Log.e(TAG, "Could not get image thumbnail", e); |
+ } finally { |
+ StreamUtil.closeQuietly(is); |
+ } |
+ |
+ return null; |
+ } |
+ |
+ @Override |
+ protected void onPostExecute(Bitmap result) { |
+ if (result == null) return; // Nothing to do, we keep the placeholder. |
+ fadeThumbnailIn(snippet, result); |
+ } |
+ }; |
+ |
+ mThumbnailFetchingTask.executeOnExecutor( |
+ AsyncTask.THREAD_POOL_EXECUTOR, snippet.mThumbnailUrl); |
+ } |
+ |
+ private void fadeThumbnailIn(SnippetArticle snippet, Bitmap thumbnail) { |
+ // We need to crop and scale the downloaded bitmap, as the ImageView we set it on won't be |
+ // able to do so when using a TransitionDrawable (as opposed to the straight bitmap). |
+ // That's a limitation of TransitionDrawable, which doesn't handle layers of varying sizes. |
+ Resources res = mThumbnailView.getResources(); |
+ int targetSize = res.getDimensionPixelSize(R.dimen.snippets_thumbnail_size); |
+ Bitmap scaledThumbnail = ThumbnailUtils.extractThumbnail( |
+ thumbnail, targetSize, targetSize, ThumbnailUtils.OPTIONS_RECYCLE_INPUT); |
+ |
+ // Store the bitmap to skip the download task next time we display this snippet. |
+ snippet.setThumbnailBitmap(scaledThumbnail); |
+ |
+ // Cross-fade between the placeholder and the thumbnail. |
+ Drawable[] layers = {mThumbnailView.getDrawable(), |
+ new BitmapDrawable(mThumbnailView.getResources(), scaledThumbnail)}; |
+ TransitionDrawable transitionDrawable = new TransitionDrawable(layers); |
+ mThumbnailView.setImageDrawable(transitionDrawable); |
+ transitionDrawable.startTransition(FADE_IN_ANIMATION_TIME_MS); |
} |
@Override |