OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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.cards; | 5 package org.chromium.chrome.browser.ntp.cards; |
6 | 6 |
7 import org.chromium.base.Callback; | 7 import org.chromium.base.Callback; |
8 import org.chromium.base.Log; | 8 import org.chromium.base.Log; |
9 import org.chromium.base.VisibleForTesting; | 9 import org.chromium.base.VisibleForTesting; |
10 import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver; | 10 import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver; |
11 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; | 11 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; |
12 import org.chromium.chrome.browser.ntp.cards.SectionList.SuggestionRanker; | |
12 import org.chromium.chrome.browser.ntp.snippets.CategoryInt; | 13 import org.chromium.chrome.browser.ntp.snippets.CategoryInt; |
13 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnu m; | 14 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnu m; |
14 import org.chromium.chrome.browser.ntp.snippets.SectionHeader; | 15 import org.chromium.chrome.browser.ntp.snippets.SectionHeader; |
15 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; | 16 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; |
16 import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder; | 17 import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder; |
17 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; | 18 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; |
18 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; | 19 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; |
19 import org.chromium.chrome.browser.offlinepages.ClientId; | 20 import org.chromium.chrome.browser.offlinepages.ClientId; |
20 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; | 21 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; |
21 import org.chromium.chrome.browser.offlinepages.OfflinePageItem; | 22 import org.chromium.chrome.browser.offlinepages.OfflinePageItem; |
22 | 23 |
23 import java.util.ArrayList; | 24 import java.util.ArrayList; |
24 import java.util.Iterator; | 25 import java.util.Iterator; |
25 import java.util.List; | 26 import java.util.List; |
26 | 27 |
27 /** | 28 /** |
28 * A group of suggestions, with a header, a status card, and a progress indicato r. This is | 29 * A group of suggestions, with a header, a status card, and a progress indicato r. This is |
29 * responsible for tracking whether its suggestions have been saved offline. | 30 * responsible for tracking whether its suggestions have been saved offline. |
30 */ | 31 */ |
31 public class SuggestionsSection extends InnerNode { | 32 public class SuggestionsSection extends InnerNode { |
32 private static final String TAG = "NtpCards"; | 33 private static final String TAG = "NtpCards"; |
33 | 34 |
34 private final Delegate mDelegate; | 35 private final Delegate mDelegate; |
35 private final SuggestionsCategoryInfo mCategoryInfo; | 36 private final SuggestionsCategoryInfo mCategoryInfo; |
36 private final OfflinePageBridge mOfflinePageBridge; | 37 private final OfflinePageBridge mOfflinePageBridge; |
38 private final SuggestionRanker mSuggestionRanker; | |
37 | 39 |
38 // Children | 40 // Children |
39 private final SectionHeader mHeader; | 41 private final SectionHeader mHeader; |
40 private final SuggestionsList mSuggestionsList; | 42 private final SuggestionsList mSuggestionsList; |
41 private final StatusItem mStatus; | 43 private final StatusItem mStatus; |
42 private final ActionItem mMoreButton; | 44 private final ActionItem mMoreButton; |
43 private final ProgressItem mProgressIndicator; | 45 private final ProgressItem mProgressIndicator; |
44 | 46 |
45 private boolean mIsNtpDestroyed; | 47 private boolean mIsNtpDestroyed; |
46 | 48 |
47 // Keep track of impressions of the suggestions so that we replace only sugg estions that | 49 // Keep track of impressions of the suggestions so that we replace only sugg estions that |
48 // have not been impressed, yet. We keep track of the first suggestion separ ately as the | 50 // have not been impressed, yet. We keep track of the first suggestion separ ately as the |
49 // first is often impressed in the form of a peeking card and we still want to be able to | 51 // first is often impressed in the form of a peeking card and we still want to be able to |
50 // replace something in this case. | 52 // replace something in this case. |
51 private boolean mFirstSuggestionSeen; | 53 private boolean mFirstSuggestionSeen; |
52 private boolean mSubsequentSuggestionsSeen; | 54 private boolean mSubsequentSuggestionsSeen; |
53 | 55 |
54 /** | 56 /** |
55 * Delegate interface that allows dismissing this section without introducin g | 57 * Delegate interface that allows dismissing this section without introducin g |
56 * a circular dependency. | 58 * a circular dependency. |
57 */ | 59 */ |
58 public interface Delegate { | 60 public interface Delegate { |
59 void dismissSection(SuggestionsSection section); | 61 void dismissSection(SuggestionsSection section); |
60 } | 62 } |
61 | 63 |
62 public SuggestionsSection(Delegate delegate, NewTabPageManager manager, | 64 public SuggestionsSection(Delegate delegate, NewTabPageManager manager, Sugg estionRanker ranker, |
63 OfflinePageBridge offlinePageBridge, SuggestionsCategoryInfo info) { | 65 OfflinePageBridge offlinePageBridge, SuggestionsCategoryInfo info) { |
64 mDelegate = delegate; | 66 mDelegate = delegate; |
65 mCategoryInfo = info; | 67 mCategoryInfo = info; |
66 mOfflinePageBridge = offlinePageBridge; | 68 mOfflinePageBridge = offlinePageBridge; |
69 mSuggestionRanker = ranker; | |
67 | 70 |
68 mHeader = new SectionHeader(info.getTitle()); | 71 mHeader = new SectionHeader(info.getTitle()); |
69 mSuggestionsList = new SuggestionsList(manager, info); | 72 mSuggestionsList = new SuggestionsList(manager, info); |
70 mStatus = StatusItem.createNoSuggestionsItem(info); | 73 mStatus = StatusItem.createNoSuggestionsItem(info); |
71 mMoreButton = new ActionItem(this); | 74 mMoreButton = new ActionItem(this); |
72 mProgressIndicator = new ProgressItem(); | 75 mProgressIndicator = new ProgressItem(); |
73 addChildren(mHeader, mSuggestionsList, mStatus, mMoreButton, mProgressIn dicator); | 76 addChildren(mHeader, mSuggestionsList, mStatus, mMoreButton, mProgressIn dicator); |
74 | 77 |
75 setupOfflinePageBridgeObserver(manager); | 78 setupOfflinePageBridgeObserver(manager); |
76 refreshChildrenVisibility(); | 79 refreshChildrenVisibility(); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
241 } | 244 } |
242 | 245 |
243 @Override | 246 @Override |
244 public void onItemRangeRemoved(TreeNode child, int index, int count) { | 247 public void onItemRangeRemoved(TreeNode child, int index, int count) { |
245 super.onItemRangeRemoved(child, index, count); | 248 super.onItemRangeRemoved(child, index, count); |
246 if (child == mSuggestionsList) refreshChildrenVisibility(); | 249 if (child == mSuggestionsList) refreshChildrenVisibility(); |
247 } | 250 } |
248 | 251 |
249 @Override | 252 @Override |
250 public void onBindViewHolder(NewTabPageViewHolder holder, int position, List <Object> payloads) { | 253 public void onBindViewHolder(NewTabPageViewHolder holder, int position, List <Object> payloads) { |
254 @ItemViewType | |
255 int viewType = getItemViewType(position); | |
256 if (viewType == ItemViewType.SNIPPET) { | |
257 childSeen(position); | |
258 } else if (viewType == ItemViewType.ACTION) { | |
259 mSuggestionRanker.rankItem((ActionItem) getChildForPosition(position ), this); | |
Bernhard Bauer
2017/01/17 17:42:31
Could we have the ActionItem itself call this?
dgn
2017/01/17 18:46:24
Done.
| |
260 } | |
251 super.onBindViewHolder(holder, position, payloads); | 261 super.onBindViewHolder(holder, position, payloads); |
252 childSeen(position); | |
253 } | 262 } |
254 | 263 |
255 /** | 264 /** |
256 * Sets the child at position {@code position} as being seen by the user. | 265 * Sets the child at position {@code position} as being seen by the user. |
257 * @param position Position in the list being shown (the first suggestion be ing at index 1, | 266 * @param position Position in the list being shown (the first suggestion be ing at index 1, |
258 * as at index 0, there is a non-suggestion). | 267 * as at index 0, there is a non-suggestion). |
259 */ | 268 */ |
260 @VisibleForTesting | 269 @VisibleForTesting |
261 public void childSeen(int position) { | 270 public void childSeen(int position) { |
Bernhard Bauer
2017/01/17 17:42:31
If this is only called for suggestions now, rename
dgn
2017/01/17 18:46:24
Reverted since actionItem calls its ranker itself.
| |
262 Log.d(TAG, "childSeen: position %d in category %d", position, mCategoryI nfo.getCategory()); | 271 Log.d(TAG, "childSeen: position %d in category %d", position, mCategoryI nfo.getCategory()); |
263 assert getStartingOffsetForChild(mSuggestionsList) == 1; | 272 assert getStartingOffsetForChild(mSuggestionsList) == 1; |
264 if (getItemViewType(position) == ItemViewType.SNIPPET) { | 273 assert getItemViewType(position) == ItemViewType.SNIPPET; |
265 // We assume all non-snippet cards come after all cards of type SNIP PET. | 274 |
266 int positionAmongSuggestions = position - 1; | 275 // We assume all non-snippet cards come after all cards of type SNIPPET. |
267 if (positionAmongSuggestions == 0) { | 276 int positionAmongSuggestions = position - 1; |
268 mFirstSuggestionSeen = true; | 277 if (positionAmongSuggestions == 0) { |
269 } else if (positionAmongSuggestions > 0) { | 278 mFirstSuggestionSeen = true; |
270 mSubsequentSuggestionsSeen = true; | 279 } else if (positionAmongSuggestions > 0) { |
271 } | 280 mSubsequentSuggestionsSeen = true; |
272 } | 281 } |
273 } | 282 } |
274 | 283 |
275 /** | 284 /** |
276 * Removes a suggestion. Does nothing if the ID is unknown. | 285 * Removes a suggestion. Does nothing if the ID is unknown. |
277 * @param idWithinCategory The ID of the suggestion to remove. | 286 * @param idWithinCategory The ID of the suggestion to remove. |
278 */ | 287 */ |
279 public void removeSuggestionById(String idWithinCategory) { | 288 public void removeSuggestionById(String idWithinCategory) { |
280 int i = 0; | 289 int i = 0; |
281 for (SnippetArticle suggestion : mSuggestionsList) { | 290 for (SnippetArticle suggestion : mSuggestionsList) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
342 Log.d(TAG, "setSuggestions: removing all suggestions"); | 351 Log.d(TAG, "setSuggestions: removing all suggestions"); |
343 mSuggestionsList.clear(); | 352 mSuggestionsList.clear(); |
344 } | 353 } |
345 } | 354 } |
346 | 355 |
347 mProgressIndicator.setVisible(SnippetsBridge.isCategoryLoading(status)); | 356 mProgressIndicator.setVisible(SnippetsBridge.isCategoryLoading(status)); |
348 | 357 |
349 mSuggestionsList.addAll(suggestions); | 358 mSuggestionsList.addAll(suggestions); |
350 | 359 |
351 for (SnippetArticle article : suggestions) { | 360 for (SnippetArticle article : suggestions) { |
361 mSuggestionRanker.rankItem(article); | |
352 if (!article.requiresExactOfflinePage()) { | 362 if (!article.requiresExactOfflinePage()) { |
353 updateSnippetOfflineAvailability(article); | 363 updateSnippetOfflineAvailability(article); |
354 } | 364 } |
355 } | 365 } |
356 | 366 |
357 refreshChildrenVisibility(); | 367 refreshChildrenVisibility(); |
358 } | 368 } |
359 | 369 |
360 private void updateSnippetOfflineAvailability(final SnippetArticle article) { | 370 private void updateSnippetOfflineAvailability(final SnippetArticle article) { |
361 // This method is not applicable to articles for which the exact offline id must specified. | 371 // This method is not applicable to articles for which the exact offline id must specified. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
441 @VisibleForTesting | 451 @VisibleForTesting |
442 ActionItem getActionItem() { | 452 ActionItem getActionItem() { |
443 return mMoreButton; | 453 return mMoreButton; |
444 } | 454 } |
445 | 455 |
446 @VisibleForTesting | 456 @VisibleForTesting |
447 StatusItem getStatusItem() { | 457 StatusItem getStatusItem() { |
448 return mStatus; | 458 return mStatus; |
449 } | 459 } |
450 } | 460 } |
OLD | NEW |