OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.ntp.snippets; | 5 package org.chromium.chrome.browser.ntp.snippets; |
6 | 6 |
7 import android.annotation.SuppressLint; | 7 import android.annotation.SuppressLint; |
8 import android.content.res.Resources; | 8 import android.content.res.Resources; |
9 import android.graphics.Bitmap; | 9 import android.graphics.Bitmap; |
10 import android.graphics.drawable.BitmapDrawable; | 10 import android.graphics.drawable.BitmapDrawable; |
(...skipping 13 matching lines...) Expand all Loading... |
24 import org.chromium.base.ApiCompatibilityUtils; | 24 import org.chromium.base.ApiCompatibilityUtils; |
25 import org.chromium.base.Callback; | 25 import org.chromium.base.Callback; |
26 import org.chromium.base.metrics.RecordHistogram; | 26 import org.chromium.base.metrics.RecordHistogram; |
27 import org.chromium.chrome.R; | 27 import org.chromium.chrome.R; |
28 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback; | 28 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback; |
29 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallbac
k; | 29 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallbac
k; |
30 import org.chromium.chrome.browser.ntp.ContextMenuManager; | 30 import org.chromium.chrome.browser.ntp.ContextMenuManager; |
31 import org.chromium.chrome.browser.ntp.ContextMenuManager.ContextMenuItemId; | 31 import org.chromium.chrome.browser.ntp.ContextMenuManager.ContextMenuItemId; |
32 import org.chromium.chrome.browser.ntp.ContextMenuManager.Delegate; | 32 import org.chromium.chrome.browser.ntp.ContextMenuManager.Delegate; |
33 import org.chromium.chrome.browser.ntp.DisplayStyleObserver; | 33 import org.chromium.chrome.browser.ntp.DisplayStyleObserver; |
34 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; | |
35 import org.chromium.chrome.browser.ntp.UiConfig; | 34 import org.chromium.chrome.browser.ntp.UiConfig; |
36 import org.chromium.chrome.browser.ntp.cards.CardViewHolder; | 35 import org.chromium.chrome.browser.ntp.cards.CardViewHolder; |
37 import org.chromium.chrome.browser.ntp.cards.CardsVariationParameters; | 36 import org.chromium.chrome.browser.ntp.cards.CardsVariationParameters; |
38 import org.chromium.chrome.browser.ntp.cards.DisplayStyleObserverAdapter; | 37 import org.chromium.chrome.browser.ntp.cards.DisplayStyleObserverAdapter; |
39 import org.chromium.chrome.browser.ntp.cards.ImpressionTracker; | 38 import org.chromium.chrome.browser.ntp.cards.ImpressionTracker; |
40 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView; | 39 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView; |
41 import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo; | 40 import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo; |
| 41 import org.chromium.chrome.browser.suggestions.ContentSuggestionsManager; |
42 import org.chromium.ui.mojom.WindowOpenDisposition; | 42 import org.chromium.ui.mojom.WindowOpenDisposition; |
43 | 43 |
44 import java.net.URI; | 44 import java.net.URI; |
45 import java.net.URISyntaxException; | 45 import java.net.URISyntaxException; |
46 import java.util.List; | 46 import java.util.List; |
47 import java.util.concurrent.TimeUnit; | 47 import java.util.concurrent.TimeUnit; |
48 | 48 |
49 /** | 49 /** |
50 * A class that represents the view for a single card snippet. | 50 * A class that represents the view for a single card snippet. |
51 */ | 51 */ |
52 public class SnippetArticleViewHolder | 52 public class SnippetArticleViewHolder |
53 extends CardViewHolder implements ImpressionTracker.Listener, ContextMen
uManager.Delegate { | 53 extends CardViewHolder implements ImpressionTracker.Listener, ContextMen
uManager.Delegate { |
54 private static final String PUBLISHER_FORMAT_STRING = "%s - %s"; | 54 private static final String PUBLISHER_FORMAT_STRING = "%s - %s"; |
55 private static final int FADE_IN_ANIMATION_TIME_MS = 300; | 55 private static final int FADE_IN_ANIMATION_TIME_MS = 300; |
56 private static final int[] FAVICON_SERVICE_SUPPORTED_SIZES = {16, 24, 32, 48
, 64}; | 56 private static final int[] FAVICON_SERVICE_SUPPORTED_SIZES = {16, 24, 32, 48
, 64}; |
57 private static final String FAVICON_SERVICE_FORMAT = | 57 private static final String FAVICON_SERVICE_FORMAT = |
58 "https://s2.googleusercontent.com/s2/favicons?domain=%s&src=chrome_n
ewtab_mobile&sz=%d&alt=404"; | 58 "https://s2.googleusercontent.com/s2/favicons?domain=%s&src=chrome_n
ewtab_mobile&sz=%d&alt=404"; |
59 | 59 |
60 public static final int PARTIAL_UPDATE_OFFLINE_ID = 1; | 60 public static final int PARTIAL_UPDATE_OFFLINE_ID = 1; |
61 | 61 |
62 private final NewTabPageManager mNewTabPageManager; | 62 private final ContentSuggestionsManager mContentSuggestionsManager; |
63 private final TextView mHeadlineTextView; | 63 private final TextView mHeadlineTextView; |
64 private final TextView mPublisherTextView; | 64 private final TextView mPublisherTextView; |
65 private final TextView mArticleSnippetTextView; | 65 private final TextView mArticleSnippetTextView; |
66 private final ImageView mThumbnailView; | 66 private final ImageView mThumbnailView; |
67 private final ImageView mOfflineBadge; | 67 private final ImageView mOfflineBadge; |
68 private final View mPublisherBar; | 68 private final View mPublisherBar; |
69 | 69 |
70 private FetchImageCallback mImageCallback; | 70 private FetchImageCallback mImageCallback; |
71 private SnippetArticle mArticle; | 71 private SnippetArticle mArticle; |
72 private SuggestionsCategoryInfo mCategoryInfo; | 72 private SuggestionsCategoryInfo mCategoryInfo; |
73 private int mPublisherFaviconSizePx; | 73 private int mPublisherFaviconSizePx; |
74 | 74 |
75 private final boolean mUseFaviconService; | 75 private final boolean mUseFaviconService; |
76 private final UiConfig mUiConfig; | 76 private final UiConfig mUiConfig; |
77 | 77 |
78 /** | 78 /** |
79 * Constructs a {@link SnippetArticleViewHolder} item used to display snippe
ts. | 79 * Constructs a {@link SnippetArticleViewHolder} item used to display snippe
ts. |
80 * | 80 * @param parent The NewTabPageRecyclerView that is going to contain the ne
wly created view. |
81 * @param parent The NewTabPageRecyclerView that is going to contain the new
ly created view. | 81 * @param contextMenuManager |
82 * @param manager The NewTabPageManager object used to open an article. | 82 * @param manager The NewTabPageManager object used to open an article. |
83 * @param uiConfig The NTP UI configuration object used to adjust the articl
e UI. | 83 * @param uiConfig The NTP UI configuration object used to adjust the articl
e UI. |
84 */ | 84 */ |
85 public SnippetArticleViewHolder(NewTabPageRecyclerView parent, NewTabPageMan
ager manager, | 85 public SnippetArticleViewHolder(NewTabPageRecyclerView parent, |
| 86 ContextMenuManager contextMenuManager, ContentSuggestionsManager man
ager, |
86 UiConfig uiConfig) { | 87 UiConfig uiConfig) { |
87 super(R.layout.new_tab_page_snippets_card, parent, uiConfig, manager); | 88 super(R.layout.new_tab_page_snippets_card, parent, uiConfig, contextMenu
Manager); |
88 | 89 |
89 mNewTabPageManager = manager; | 90 mContentSuggestionsManager = manager; |
90 mThumbnailView = (ImageView) itemView.findViewById(R.id.article_thumbnai
l); | 91 mThumbnailView = (ImageView) itemView.findViewById(R.id.article_thumbnai
l); |
91 mHeadlineTextView = (TextView) itemView.findViewById(R.id.article_headli
ne); | 92 mHeadlineTextView = (TextView) itemView.findViewById(R.id.article_headli
ne); |
92 mPublisherTextView = (TextView) itemView.findViewById(R.id.article_publi
sher); | 93 mPublisherTextView = (TextView) itemView.findViewById(R.id.article_publi
sher); |
93 mArticleSnippetTextView = (TextView) itemView.findViewById(R.id.article_
snippet); | 94 mArticleSnippetTextView = (TextView) itemView.findViewById(R.id.article_
snippet); |
94 mPublisherBar = itemView.findViewById(R.id.publisher_bar); | 95 mPublisherBar = itemView.findViewById(R.id.publisher_bar); |
95 mOfflineBadge = (ImageView) itemView.findViewById(R.id.offline_icon); | 96 mOfflineBadge = (ImageView) itemView.findViewById(R.id.offline_icon); |
96 | 97 |
97 new ImpressionTracker(itemView, this); | 98 new ImpressionTracker(itemView, this); |
98 | 99 |
99 mUiConfig = uiConfig; | 100 mUiConfig = uiConfig; |
100 new DisplayStyleObserverAdapter(itemView, uiConfig, new DisplayStyleObse
rver() { | 101 new DisplayStyleObserverAdapter(itemView, uiConfig, new DisplayStyleObse
rver() { |
101 @Override | 102 @Override |
102 public void onDisplayStyleChanged(@UiConfig.DisplayStyle int newDisp
layStyle) { | 103 public void onDisplayStyleChanged(@UiConfig.DisplayStyle int newDisp
layStyle) { |
103 updateLayout(); | 104 updateLayout(); |
104 } | 105 } |
105 }); | 106 }); |
106 | 107 |
107 mUseFaviconService = CardsVariationParameters.isFaviconServiceEnabled(); | 108 mUseFaviconService = CardsVariationParameters.isFaviconServiceEnabled(); |
108 } | 109 } |
109 | 110 |
110 @Override | 111 @Override |
111 public void onImpression() { | 112 public void onImpression() { |
112 if (mArticle != null && mArticle.trackImpression()) { | 113 if (mArticle != null && mArticle.trackImpression()) { |
113 mNewTabPageManager.trackSnippetImpression(mArticle); | 114 mContentSuggestionsManager.trackSnippetImpression(mArticle); |
114 mRecyclerView.onSnippetImpression(); | 115 mRecyclerView.onSnippetImpression(); |
115 } | 116 } |
116 } | 117 } |
117 | 118 |
118 @Override | 119 @Override |
119 public void onCardTapped() { | 120 public void onCardTapped() { |
120 mNewTabPageManager.openSnippet(WindowOpenDisposition.CURRENT_TAB, mArtic
le); | 121 mContentSuggestionsManager.openSnippet(WindowOpenDisposition.CURRENT_TAB
, mArticle); |
121 } | 122 } |
122 | 123 |
123 @Override | 124 @Override |
124 public void openItem(int windowDisposition) { | 125 public void openItem(int windowDisposition) { |
125 mNewTabPageManager.openSnippet(windowDisposition, mArticle); | 126 mContentSuggestionsManager.openSnippet(windowDisposition, mArticle); |
126 } | 127 } |
127 | 128 |
128 @Override | 129 @Override |
129 public void removeItem() { | 130 public void removeItem() { |
130 getRecyclerView().dismissItemWithAnimation(this); | 131 getRecyclerView().dismissItemWithAnimation(this); |
131 } | 132 } |
132 | 133 |
133 @Override | 134 @Override |
134 public String getUrl() { | 135 public String getUrl() { |
135 return mArticle.mUrl; | 136 return mArticle.mUrl; |
136 } | 137 } |
137 | 138 |
138 @Override | 139 @Override |
139 public boolean isItemSupported(@ContextMenuItemId int menuItemId) { | 140 public boolean isItemSupported(@ContextMenuItemId int menuItemId) { |
140 if (mArticle.isDownload()) { | 141 if (mArticle.isDownload()) { |
141 if (menuItemId == ContextMenuManager.ID_OPEN_IN_INCOGNITO_TAB) retur
n false; | 142 if (menuItemId == ContextMenuManager.ID_OPEN_IN_INCOGNITO_TAB) retur
n false; |
142 if (menuItemId == ContextMenuManager.ID_SAVE_FOR_OFFLINE) return fal
se; | 143 if (menuItemId == ContextMenuManager.ID_SAVE_FOR_OFFLINE) return fal
se; |
143 return true; | 144 return true; |
144 } | 145 } |
145 if (mArticle.isRecentTab()) { | 146 if (mArticle.isRecentTab()) { |
146 if (menuItemId == ContextMenuManager.ID_REMOVE) return true; | 147 if (menuItemId == ContextMenuManager.ID_REMOVE) return true; |
147 return false; | 148 return false; |
148 } | 149 } |
149 return true; | 150 return true; |
150 } | 151 } |
151 | 152 |
152 @Override | 153 @Override |
153 public void onContextMenuCreated() { | 154 public void onContextMenuCreated() { |
154 mNewTabPageManager.trackSnippetMenuOpened(mArticle); | 155 mContentSuggestionsManager.trackSnippetMenuOpened(mArticle); |
155 } | 156 } |
156 | 157 |
157 @Override | 158 @Override |
158 protected Delegate getContextMenuDelegate() { | 159 protected Delegate getContextMenuDelegate() { |
159 return this; | 160 return this; |
160 } | 161 } |
161 | 162 |
162 /** | 163 /** |
163 * Updates the layout taking into account screen dimensions and the type of
snippet displayed. | 164 * Updates the layout taking into account screen dimensions and the type of
snippet displayed. |
164 */ | 165 */ |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 cancelImageFetch(); | 252 cancelImageFetch(); |
252 | 253 |
253 // If the article has a thumbnail already, reuse it. Otherwise start a f
etch. | 254 // If the article has a thumbnail already, reuse it. Otherwise start a f
etch. |
254 // mThumbnailView's visibility is modified in updateLayout(). | 255 // mThumbnailView's visibility is modified in updateLayout(). |
255 if (mThumbnailView.getVisibility() == View.VISIBLE) { | 256 if (mThumbnailView.getVisibility() == View.VISIBLE) { |
256 if (mArticle.getThumbnailBitmap() != null) { | 257 if (mArticle.getThumbnailBitmap() != null) { |
257 mThumbnailView.setImageBitmap(mArticle.getThumbnailBitmap()); | 258 mThumbnailView.setImageBitmap(mArticle.getThumbnailBitmap()); |
258 } else { | 259 } else { |
259 mThumbnailView.setImageResource(R.drawable.ic_snippet_thumbnail_
placeholder); | 260 mThumbnailView.setImageResource(R.drawable.ic_snippet_thumbnail_
placeholder); |
260 mImageCallback = new FetchImageCallback(this, mArticle); | 261 mImageCallback = new FetchImageCallback(this, mArticle); |
261 mNewTabPageManager.getSuggestionsSource() | 262 mContentSuggestionsManager.getSuggestionsSource().fetchSuggestio
nImage( |
262 .fetchSuggestionImage(mArticle, mImageCallback); | 263 mArticle, mImageCallback); |
263 } | 264 } |
264 } | 265 } |
265 | 266 |
266 // Set the favicon of the publisher. | 267 // Set the favicon of the publisher. |
267 try { | 268 try { |
268 fetchFaviconFromLocalCache(new URI(mArticle.mUrl), true); | 269 fetchFaviconFromLocalCache(new URI(mArticle.mUrl), true); |
269 } catch (URISyntaxException e) { | 270 } catch (URISyntaxException e) { |
270 setDefaultFaviconOnView(); | 271 setDefaultFaviconOnView(); |
271 } | 272 } |
272 | 273 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 // image may have transparency and we don't want the previous image show
ing up behind. | 338 // image may have transparency and we don't want the previous image show
ing up behind. |
338 Drawable[] layers = {mThumbnailView.getDrawable(), | 339 Drawable[] layers = {mThumbnailView.getDrawable(), |
339 new BitmapDrawable(mThumbnailView.getResources(), scaledThumbnai
l)}; | 340 new BitmapDrawable(mThumbnailView.getResources(), scaledThumbnai
l)}; |
340 TransitionDrawable transitionDrawable = new TransitionDrawable(layers); | 341 TransitionDrawable transitionDrawable = new TransitionDrawable(layers); |
341 mThumbnailView.setImageDrawable(transitionDrawable); | 342 mThumbnailView.setImageDrawable(transitionDrawable); |
342 transitionDrawable.setCrossFadeEnabled(true); | 343 transitionDrawable.setCrossFadeEnabled(true); |
343 transitionDrawable.startTransition(FADE_IN_ANIMATION_TIME_MS); | 344 transitionDrawable.startTransition(FADE_IN_ANIMATION_TIME_MS); |
344 } | 345 } |
345 | 346 |
346 private void fetchFaviconFromLocalCache(final URI snippetUri, final boolean
fallbackToService) { | 347 private void fetchFaviconFromLocalCache(final URI snippetUri, final boolean
fallbackToService) { |
347 mNewTabPageManager.getLocalFaviconImageForURL( | 348 mContentSuggestionsManager.getLocalFaviconImageForURL( |
348 getSnippetDomain(snippetUri), mPublisherFaviconSizePx, new Favic
onImageCallback() { | 349 getSnippetDomain(snippetUri), mPublisherFaviconSizePx, new Favic
onImageCallback() { |
349 @Override | 350 @Override |
350 public void onFaviconAvailable(Bitmap image, String iconUrl)
{ | 351 public void onFaviconAvailable(Bitmap image, String iconUrl)
{ |
351 if (image == null && fallbackToService) { | 352 if (image == null && fallbackToService) { |
352 fetchFaviconFromService(snippetUri); | 353 fetchFaviconFromService(snippetUri); |
353 return; | 354 return; |
354 } | 355 } |
355 setFaviconOnView(image); | 356 setFaviconOnView(image); |
356 } | 357 } |
357 }); | 358 }); |
358 } | 359 } |
359 | 360 |
360 // TODO(crbug.com/635567): Fix this properly. | 361 // TODO(crbug.com/635567): Fix this properly. |
361 @SuppressLint("DefaultLocale") | 362 @SuppressLint("DefaultLocale") |
362 private void fetchFaviconFromService(final URI snippetUri) { | 363 private void fetchFaviconFromService(final URI snippetUri) { |
363 // Show the default favicon immediately. | 364 // Show the default favicon immediately. |
364 setDefaultFaviconOnView(); | 365 setDefaultFaviconOnView(); |
365 | 366 |
366 if (!mUseFaviconService) return; | 367 if (!mUseFaviconService) return; |
367 int sizePx = getFaviconServiceSupportedSize(); | 368 int sizePx = getFaviconServiceSupportedSize(); |
368 if (sizePx == 0) return; | 369 if (sizePx == 0) return; |
369 | 370 |
370 // Replace the default icon by another one from the service when it is f
etched. | 371 // Replace the default icon by another one from the service when it is f
etched. |
371 mNewTabPageManager.ensureIconIsAvailable( | 372 mContentSuggestionsManager.ensureIconIsAvailable( |
372 getSnippetDomain(snippetUri), // Store to the cache for the whol
e domain. | 373 getSnippetDomain(snippetUri), // Store to the cache for the whol
e domain. |
373 String.format(FAVICON_SERVICE_FORMAT, snippetUri.getHost(), size
Px), | 374 String.format(FAVICON_SERVICE_FORMAT, snippetUri.getHost(), size
Px), |
374 /*useLargeIcon=*/false, /*isTemporary=*/true, new IconAvailabili
tyCallback() { | 375 /*useLargeIcon=*/false, /*isTemporary=*/true, new IconAvailabili
tyCallback() { |
375 @Override | 376 @Override |
376 public void onIconAvailabilityChecked(boolean newlyAvailable
) { | 377 public void onIconAvailabilityChecked(boolean newlyAvailable
) { |
377 if (!newlyAvailable) return; | 378 if (!newlyAvailable) return; |
378 // The download succeeded, the favicon is in the cache;
fetch it. | 379 // The download succeeded, the favicon is in the cache;
fetch it. |
379 fetchFaviconFromLocalCache(snippetUri, /*fallbackToServi
ce=*/false); | 380 fetchFaviconFromLocalCache(snippetUri, /*fallbackToServi
ce=*/false); |
380 } | 381 } |
381 }); | 382 }); |
(...skipping 29 matching lines...) Expand all Loading... |
411 ApiCompatibilityUtils.setCompoundDrawablesRelative( | 412 ApiCompatibilityUtils.setCompoundDrawablesRelative( |
412 mPublisherTextView, drawable, null, null, null); | 413 mPublisherTextView, drawable, null, null, null); |
413 mPublisherTextView.setVisibility(View.VISIBLE); | 414 mPublisherTextView.setVisibility(View.VISIBLE); |
414 } | 415 } |
415 | 416 |
416 @Override | 417 @Override |
417 public boolean isDismissable() { | 418 public boolean isDismissable() { |
418 return !isPeeking(); | 419 return !isPeeking(); |
419 } | 420 } |
420 } | 421 } |
OLD | NEW |