| 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.Log; | 7 import org.chromium.base.Log; |
| 8 import org.chromium.base.VisibleForTesting; | 8 import org.chromium.base.VisibleForTesting; |
| 9 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; | 9 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; |
| 10 import org.chromium.chrome.browser.ntp.snippets.CategoryInt; | 10 import org.chromium.chrome.browser.ntp.snippets.CategoryInt; |
| 11 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; | 11 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; |
| 12 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnu
m; | 12 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnu
m; |
| 13 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; | 13 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; |
| 14 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; | 14 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; |
| 15 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig; | 15 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig; |
| 16 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; | 16 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; |
| 17 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; | 17 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; |
| 18 import org.chromium.chrome.browser.suggestions.SuggestionsRanker; |
| 18 | 19 |
| 19 import java.util.LinkedHashMap; | 20 import java.util.LinkedHashMap; |
| 20 import java.util.List; | 21 import java.util.List; |
| 21 import java.util.Map; | 22 import java.util.Map; |
| 22 | 23 |
| 23 /** | 24 /** |
| 24 * A node in the tree containing a list of all suggestions sections. It listens
to changes in the | 25 * A node in the tree containing a list of all suggestions sections. It listens
to changes in the |
| 25 * suggestions source and updates the corresponding sections. | 26 * suggestions source and updates the corresponding sections. |
| 26 */ | 27 */ |
| 27 public class SectionList | 28 public class SectionList |
| 28 extends InnerNode implements SuggestionsSource.Observer, SuggestionsSect
ion.Delegate { | 29 extends InnerNode implements SuggestionsSource.Observer, SuggestionsSect
ion.Delegate { |
| 29 private static final String TAG = "Ntp"; | 30 private static final String TAG = "Ntp"; |
| 30 | 31 |
| 31 /** Maps suggestion categories to sections, with stable iteration ordering.
*/ | 32 /** Maps suggestion categories to sections, with stable iteration ordering.
*/ |
| 32 private final Map<Integer, SuggestionsSection> mSections = new LinkedHashMap
<>(); | 33 private final Map<Integer, SuggestionsSection> mSections = new LinkedHashMap
<>(); |
| 33 private final NewTabPageManager mNewTabPageManager; | 34 private final NewTabPageManager mNewTabPageManager; |
| 34 private final OfflinePageBridge mOfflinePageBridge; | 35 private final OfflinePageBridge mOfflinePageBridge; |
| 36 private final SuggestionsRanker mSuggestionsRanker; |
| 35 | 37 |
| 36 public SectionList(NewTabPageManager newTabPageManager, OfflinePageBridge of
flinePageBridge) { | 38 public SectionList(NewTabPageManager newTabPageManager, OfflinePageBridge of
flinePageBridge) { |
| 39 mSuggestionsRanker = new SuggestionsRanker(); |
| 37 mNewTabPageManager = newTabPageManager; | 40 mNewTabPageManager = newTabPageManager; |
| 38 mNewTabPageManager.getSuggestionsSource().setObserver(this); | 41 mNewTabPageManager.getSuggestionsSource().setObserver(this); |
| 42 mNewTabPageManager.getSuggestionsMetricsReporter().setRanker(mSuggestion
sRanker); |
| 39 mOfflinePageBridge = offlinePageBridge; | 43 mOfflinePageBridge = offlinePageBridge; |
| 40 resetSections(/* alwaysAllowEmptySections = */ false); | 44 resetSections(/* alwaysAllowEmptySections = */ false); |
| 41 } | 45 } |
| 42 | 46 |
| 43 /** | 47 /** |
| 44 * Resets the sections, reloading the whole new tab page content. | 48 * Resets the sections, reloading the whole new tab page content. |
| 45 * @param alwaysAllowEmptySections Whether sections are always allowed to be
displayed when | 49 * @param alwaysAllowEmptySections Whether sections are always allowed to be
displayed when |
| 46 * they are empty, even when they are normally not. | 50 * they are empty, even when they are normally not. |
| 47 */ | 51 */ |
| 48 public void resetSections(boolean alwaysAllowEmptySections) { | 52 public void resetSections(boolean alwaysAllowEmptySections) { |
| 49 removeAllSections(); | 53 removeAllSections(); |
| 50 | 54 |
| 51 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsS
ource(); | 55 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsS
ource(); |
| 52 int[] categories = suggestionsSource.getCategories(); | 56 int[] categories = suggestionsSource.getCategories(); |
| 53 int[] suggestionsPerCategory = new int[categories.length]; | 57 int[] suggestionsPerCategory = new int[categories.length]; |
| 54 int categoryIndex = 0; | 58 int categoryIndex = 0; |
| 55 for (int category : categories) { | 59 for (int category : categories) { |
| 56 int categoryStatus = suggestionsSource.getCategoryStatus(category); | 60 int categoryStatus = suggestionsSource.getCategoryStatus(category); |
| 57 if (categoryStatus == CategoryStatus.LOADING_ERROR | 61 if (categoryStatus == CategoryStatus.LOADING_ERROR |
| 58 || categoryStatus == CategoryStatus.NOT_PROVIDED | 62 || categoryStatus == CategoryStatus.NOT_PROVIDED |
| 59 || categoryStatus == CategoryStatus.CATEGORY_EXPLICITLY_DISA
BLED) | 63 || categoryStatus == CategoryStatus.CATEGORY_EXPLICITLY_DISA
BLED) |
| 60 continue; | 64 continue; |
| 61 | 65 |
| 62 suggestionsPerCategory[categoryIndex] = | 66 suggestionsPerCategory[categoryIndex] = |
| 63 resetSection(category, categoryStatus, alwaysAllowEmptySecti
ons); | 67 resetSection(category, categoryStatus, alwaysAllowEmptySecti
ons); |
| 64 SuggestionsSection section = mSections.get(category); | |
| 65 if (section != null) section.setCategoryIndex(categoryIndex); | |
| 66 ++categoryIndex; | 68 ++categoryIndex; |
| 67 } | 69 } |
| 68 | 70 |
| 69 mNewTabPageManager.trackSnippetsPageImpression(categories, suggestionsPe
rCategory); | 71 mNewTabPageManager.getSuggestionsMetricsReporter().onPageShown( |
| 72 categories, suggestionsPerCategory); |
| 70 } | 73 } |
| 71 | 74 |
| 72 /** | 75 /** |
| 73 * Resets the section for {@code category}. Removes the section if there are
no suggestions for | 76 * Resets the section for {@code category}. Removes the section if there are
no suggestions for |
| 74 * it and it is not allowed to be empty. Otherwise, creates the section if i
t is not present | 77 * it and it is not allowed to be empty. Otherwise, creates the section if i
t is not present |
| 75 * yet. Sets the available suggestions on the section. | 78 * yet. Sets the available suggestions on the section. |
| 76 * @param category The category for which the section must be reset. | 79 * @param category The category for which the section must be reset. |
| 77 * @param categoryStatus The category status. | 80 * @param categoryStatus The category status. |
| 78 * @param alwaysAllowEmptySections Whether sections are always allowed to be
displayed when | 81 * @param alwaysAllowEmptySections Whether sections are always allowed to be
displayed when |
| 79 * they are empty, even when they are normally not. | 82 * they are empty, even when they are normally not. |
| 80 * @return The number of suggestions for the section. | 83 * @return The number of suggestions for the section. |
| 81 */ | 84 */ |
| 82 private int resetSection(@CategoryInt int category, @CategoryStatusEnum int
categoryStatus, | 85 private int resetSection(@CategoryInt int category, @CategoryStatusEnum int
categoryStatus, |
| 83 boolean alwaysAllowEmptySections) { | 86 boolean alwaysAllowEmptySections) { |
| 84 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsS
ource(); | 87 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsS
ource(); |
| 85 List<SnippetArticle> suggestions = suggestionsSource.getSuggestionsForCa
tegory(category); | 88 List<SnippetArticle> suggestions = suggestionsSource.getSuggestionsForCa
tegory(category); |
| 86 SuggestionsCategoryInfo info = suggestionsSource.getCategoryInfo(categor
y); | 89 SuggestionsCategoryInfo info = suggestionsSource.getCategoryInfo(categor
y); |
| 87 | 90 |
| 88 SuggestionsSection section = mSections.get(category); | 91 SuggestionsSection section = mSections.get(category); |
| 89 | 92 |
| 90 // Do not show an empty section if not allowed. | 93 // Do not show an empty section if not allowed. |
| 91 if (suggestions.isEmpty() && !info.showIfEmpty() && !alwaysAllowEmptySec
tions) { | 94 if (suggestions.isEmpty() && !info.showIfEmpty() && !alwaysAllowEmptySec
tions) { |
| 92 if (section != null) removeSection(section); | 95 if (section != null) removeSection(section); |
| 93 return 0; | 96 return 0; |
| 94 } | 97 } |
| 95 | 98 |
| 96 // Create the section if needed. | 99 // Create the section if needed. |
| 97 if (section == null) { | 100 if (section == null) { |
| 98 section = new SuggestionsSection(this, mNewTabPageManager, mOfflineP
ageBridge, info); | 101 section = new SuggestionsSection( |
| 102 this, mNewTabPageManager, mSuggestionsRanker, mOfflinePageBr
idge, info); |
| 99 mSections.put(category, section); | 103 mSections.put(category, section); |
| 104 mSuggestionsRanker.registerCategory(category); |
| 100 addChild(section); | 105 addChild(section); |
| 101 } | 106 } |
| 102 | 107 |
| 103 // Set the new suggestions. | 108 // Set the new suggestions. |
| 104 setSuggestions(category, suggestions, categoryStatus, /* replaceExisting
= */ true); | 109 setSuggestions(category, suggestions, categoryStatus, /* replaceExisting
= */ true); |
| 105 | 110 |
| 106 return suggestions.size(); | 111 return suggestions.size(); |
| 107 } | 112 } |
| 108 | 113 |
| 109 @Override | 114 @Override |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 * may have no or only partial effect if changing the list of suggestions is
not allowed (e.g. | 184 * may have no or only partial effect if changing the list of suggestions is
not allowed (e.g. |
| 180 * because the user has already seen the suggestions). | 185 * because the user has already seen the suggestions). |
| 181 * @param category The category for which the suggestions should be set. | 186 * @param category The category for which the suggestions should be set. |
| 182 * @param suggestions The new list of suggestions for the given category. | 187 * @param suggestions The new list of suggestions for the given category. |
| 183 * @param status The new category status. | 188 * @param status The new category status. |
| 184 * @param replaceExisting If true, {@code suggestions} replace the current l
ist of suggestions. | 189 * @param replaceExisting If true, {@code suggestions} replace the current l
ist of suggestions. |
| 185 * If false, {@code suggestions} are appended to current list of suggestions
. | 190 * If false, {@code suggestions} are appended to current list of suggestions
. |
| 186 */ | 191 */ |
| 187 private void setSuggestions(@CategoryInt int category, List<SnippetArticle>
suggestions, | 192 private void setSuggestions(@CategoryInt int category, List<SnippetArticle>
suggestions, |
| 188 @CategoryStatusEnum int status, boolean replaceExisting) { | 193 @CategoryStatusEnum int status, boolean replaceExisting) { |
| 189 // Count the number of suggestions before this category. | |
| 190 int globalPositionOffset = 0; | |
| 191 for (Map.Entry<Integer, SuggestionsSection> entry : mSections.entrySet()
) { | |
| 192 if (entry.getKey() == category) break; | |
| 193 globalPositionOffset += entry.getValue().getSuggestionsCount(); | |
| 194 } | |
| 195 // Assign global indices to the new suggestions. | |
| 196 for (SnippetArticle suggestion : suggestions) { | |
| 197 suggestion.mGlobalPosition = globalPositionOffset + suggestion.mPosi
tion; | |
| 198 } | |
| 199 | |
| 200 mSections.get(category).setSuggestions(suggestions, status, replaceExist
ing); | 194 mSections.get(category).setSuggestions(suggestions, status, replaceExist
ing); |
| 201 } | 195 } |
| 202 | 196 |
| 203 private boolean canLoadSuggestions(@CategoryInt int category, @CategoryStatu
sEnum int status) { | 197 private boolean canLoadSuggestions(@CategoryInt int category, @CategoryStatu
sEnum int status) { |
| 204 // We never want to add suggestions from unknown categories. | 198 // We never want to add suggestions from unknown categories. |
| 205 if (!mSections.containsKey(category)) return false; | 199 if (!mSections.containsKey(category)) return false; |
| 206 | 200 |
| 207 // The status may have changed while the suggestions were loading, perha
ps they should not | 201 // The status may have changed while the suggestions were loading, perha
ps they should not |
| 208 // be displayed any more. | 202 // be displayed any more. |
| 209 if (!SnippetsBridge.isCategoryEnabled(status)) { | 203 if (!SnippetsBridge.isCategoryEnabled(status)) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 * @return Whether the list of sections is empty. | 245 * @return Whether the list of sections is empty. |
| 252 */ | 246 */ |
| 253 public boolean isEmpty() { | 247 public boolean isEmpty() { |
| 254 return mSections.isEmpty(); | 248 return mSections.isEmpty(); |
| 255 } | 249 } |
| 256 | 250 |
| 257 SuggestionsSection getSectionForTesting(@CategoryInt int categoryId) { | 251 SuggestionsSection getSectionForTesting(@CategoryInt int categoryId) { |
| 258 return mSections.get(categoryId); | 252 return mSections.get(categoryId); |
| 259 } | 253 } |
| 260 } | 254 } |
| OLD | NEW |