Chromium Code Reviews| 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..cf8d657a126e578077524fedd0cf7d408bd40fba 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,11 +29,18 @@ |
| 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; |
| + private AsyncTask<String, Void, Bitmap> mThumbnailFetchingTask; |
| public TextView mHeadlineTextView; |
| public TextView mPublisherTextView; |
| public TextView mArticleSnippetTextView; |
| @@ -90,7 +107,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 { |
|
dgn
2016/04/12 13:40:21
API 19 minimum for try-with-resources :(
Bernhard Bauer
2016/04/12 13:46:19
Yeah, I was wondering about that. (Sorry, should h
|
| + 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 |