| 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
|
|
|