Chromium Code Reviews| 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; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 * suggestions source and updates the corresponding sections. | 25 * suggestions source and updates the corresponding sections. |
| 26 */ | 26 */ |
| 27 public class SectionList | 27 public class SectionList |
| 28 extends InnerNode implements SuggestionsSource.Observer, SuggestionsSect ion.Delegate { | 28 extends InnerNode implements SuggestionsSource.Observer, SuggestionsSect ion.Delegate { |
| 29 private static final String TAG = "Ntp"; | 29 private static final String TAG = "Ntp"; |
| 30 | 30 |
| 31 /** Maps suggestion categories to sections, with stable iteration ordering. */ | 31 /** Maps suggestion categories to sections, with stable iteration ordering. */ |
| 32 private final Map<Integer, SuggestionsSection> mSections = new LinkedHashMap <>(); | 32 private final Map<Integer, SuggestionsSection> mSections = new LinkedHashMap <>(); |
| 33 private final NewTabPageManager mNewTabPageManager; | 33 private final NewTabPageManager mNewTabPageManager; |
| 34 private final OfflinePageBridge mOfflinePageBridge; | 34 private final OfflinePageBridge mOfflinePageBridge; |
| 35 private final SuggestionRanker mSuggestionRanker; | |
| 35 | 36 |
| 36 public SectionList(NewTabPageManager newTabPageManager, OfflinePageBridge of flinePageBridge) { | 37 public SectionList(NewTabPageManager newTabPageManager, OfflinePageBridge of flinePageBridge) { |
| 38 mSuggestionRanker = new SuggestionRanker(); | |
| 37 mNewTabPageManager = newTabPageManager; | 39 mNewTabPageManager = newTabPageManager; |
| 38 mNewTabPageManager.getSuggestionsSource().setObserver(this); | 40 mNewTabPageManager.getSuggestionsSource().setObserver(this); |
| 39 mOfflinePageBridge = offlinePageBridge; | 41 mOfflinePageBridge = offlinePageBridge; |
| 40 resetSections(/* alwaysAllowEmptySections = */ false); | 42 resetSections(/* alwaysAllowEmptySections = */ false); |
| 41 } | 43 } |
| 42 | 44 |
| 43 /** | 45 /** |
| 44 * Resets the sections, reloading the whole new tab page content. | 46 * Resets the sections, reloading the whole new tab page content. |
| 45 * @param alwaysAllowEmptySections Whether sections are always allowed to be displayed when | 47 * @param alwaysAllowEmptySections Whether sections are always allowed to be displayed when |
| 46 * they are empty, even when they are normally not. | 48 * they are empty, even when they are normally not. |
| 47 */ | 49 */ |
| 48 public void resetSections(boolean alwaysAllowEmptySections) { | 50 public void resetSections(boolean alwaysAllowEmptySections) { |
| 49 removeAllSections(); | 51 removeAllSections(); |
| 50 | 52 |
| 51 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsS ource(); | 53 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsS ource(); |
| 52 int[] categories = suggestionsSource.getCategories(); | 54 int[] categories = suggestionsSource.getCategories(); |
| 53 int[] suggestionsPerCategory = new int[categories.length]; | 55 int[] suggestionsPerCategory = new int[categories.length]; |
| 54 int i = 0; | 56 int i = 0; |
| 55 for (int category : categories) { | 57 for (int category : categories) { |
| 56 int categoryStatus = suggestionsSource.getCategoryStatus(category); | 58 int categoryStatus = suggestionsSource.getCategoryStatus(category); |
| 57 if (categoryStatus == CategoryStatus.LOADING_ERROR | 59 if (categoryStatus == CategoryStatus.LOADING_ERROR |
| 58 || categoryStatus == CategoryStatus.NOT_PROVIDED | 60 || categoryStatus == CategoryStatus.NOT_PROVIDED |
| 59 || categoryStatus == CategoryStatus.CATEGORY_EXPLICITLY_DISA BLED) | 61 || categoryStatus == CategoryStatus.CATEGORY_EXPLICITLY_DISA BLED) |
| 60 continue; | 62 continue; |
| 61 | 63 |
| 62 suggestionsPerCategory[i++] = | 64 suggestionsPerCategory[i++] = |
| 63 resetSection(category, categoryStatus, alwaysAllowEmptySecti ons); | 65 resetSection(category, categoryStatus, alwaysAllowEmptySecti ons); |
| 64 } | 66 } |
| 65 | 67 |
| 66 mNewTabPageManager.trackSnippetsPageImpression(categories, suggestionsPe rCategory); | 68 mNewTabPageManager.getSuggestionsMetricsReporter().onPageShown( |
| 69 categories, suggestionsPerCategory); | |
| 67 } | 70 } |
| 68 | 71 |
| 69 /** | 72 /** |
| 70 * Resets the section for {@code category}. Removes the section if there are no suggestions for | 73 * Resets the section for {@code category}. Removes the section if there are no suggestions for |
| 71 * it and it is not allowed to be empty. Otherwise, creates the section if i t is not present | 74 * it and it is not allowed to be empty. Otherwise, creates the section if i t is not present |
| 72 * yet. Sets the available suggestions on the section. | 75 * yet. Sets the available suggestions on the section. |
| 73 * @param category The category for which the section must be reset. | 76 * @param category The category for which the section must be reset. |
| 74 * @param categoryStatus The category status. | 77 * @param categoryStatus The category status. |
| 75 * @param alwaysAllowEmptySections Whether sections are always allowed to be displayed when | 78 * @param alwaysAllowEmptySections Whether sections are always allowed to be displayed when |
| 76 * they are empty, even when they are normally not. | 79 * they are empty, even when they are normally not. |
| 77 * @return The number of suggestions for the section. | 80 * @return The number of suggestions for the section. |
| 78 */ | 81 */ |
| 79 private int resetSection(@CategoryInt int category, @CategoryStatusEnum int categoryStatus, | 82 private int resetSection(@CategoryInt int category, @CategoryStatusEnum int categoryStatus, |
| 80 boolean alwaysAllowEmptySections) { | 83 boolean alwaysAllowEmptySections) { |
| 81 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsS ource(); | 84 SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsS ource(); |
| 82 List<SnippetArticle> suggestions = suggestionsSource.getSuggestionsForCa tegory(category); | 85 List<SnippetArticle> suggestions = suggestionsSource.getSuggestionsForCa tegory(category); |
| 83 SuggestionsCategoryInfo info = suggestionsSource.getCategoryInfo(categor y); | 86 SuggestionsCategoryInfo info = suggestionsSource.getCategoryInfo(categor y); |
| 84 | 87 |
| 85 SuggestionsSection section = mSections.get(category); | 88 SuggestionsSection section = mSections.get(category); |
| 86 | 89 |
| 87 // Do not show an empty section if not allowed. | 90 // Do not show an empty section if not allowed. |
| 88 if (suggestions.isEmpty() && !info.showIfEmpty() && !alwaysAllowEmptySec tions) { | 91 if (suggestions.isEmpty() && !info.showIfEmpty() && !alwaysAllowEmptySec tions) { |
| 89 if (section != null) removeSection(section); | 92 if (section != null) removeSection(section); |
| 90 return 0; | 93 return 0; |
| 91 } | 94 } |
| 92 | 95 |
| 93 // Create the section if needed. | 96 // Create the section if needed. |
| 94 if (section == null) { | 97 if (section == null) { |
| 95 section = new SuggestionsSection(this, mNewTabPageManager, mOfflineP ageBridge, info); | 98 section = new SuggestionsSection( |
| 99 this, mNewTabPageManager, mSuggestionRanker, mOfflinePageBri dge, info); | |
| 96 mSections.put(category, section); | 100 mSections.put(category, section); |
| 101 mSuggestionRanker.registerCategory(category); | |
| 97 addChild(section); | 102 addChild(section); |
| 98 } | 103 } |
| 99 | 104 |
| 100 // Set the new suggestions. | 105 // Set the new suggestions. |
| 101 setSuggestions(category, suggestions, categoryStatus, /* replaceExisting = */ true); | 106 setSuggestions(category, suggestions, categoryStatus, /* replaceExisting = */ true); |
| 102 | 107 |
| 103 return suggestions.size(); | 108 return suggestions.size(); |
| 104 } | 109 } |
| 105 | 110 |
| 106 @Override | 111 @Override |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 176 * may have no or only partial effect if changing the list of suggestions is not allowed (e.g. | 181 * may have no or only partial effect if changing the list of suggestions is not allowed (e.g. |
| 177 * because the user has already seen the suggestions). | 182 * because the user has already seen the suggestions). |
| 178 * @param category The category for which the suggestions should be set. | 183 * @param category The category for which the suggestions should be set. |
| 179 * @param suggestions The new list of suggestions for the given category. | 184 * @param suggestions The new list of suggestions for the given category. |
| 180 * @param status The new category status. | 185 * @param status The new category status. |
| 181 * @param replaceExisting If true, {@code suggestions} replace the current l ist of suggestions. | 186 * @param replaceExisting If true, {@code suggestions} replace the current l ist of suggestions. |
| 182 * If false, {@code suggestions} are appended to current list of suggestions . | 187 * If false, {@code suggestions} are appended to current list of suggestions . |
| 183 */ | 188 */ |
| 184 private void setSuggestions(@CategoryInt int category, List<SnippetArticle> suggestions, | 189 private void setSuggestions(@CategoryInt int category, List<SnippetArticle> suggestions, |
| 185 @CategoryStatusEnum int status, boolean replaceExisting) { | 190 @CategoryStatusEnum int status, boolean replaceExisting) { |
| 186 // Count the number of suggestions before this category. | |
| 187 int globalPositionOffset = 0; | |
| 188 for (Map.Entry<Integer, SuggestionsSection> entry : mSections.entrySet() ) { | |
| 189 if (entry.getKey() == category) break; | |
| 190 globalPositionOffset += entry.getValue().getSuggestionsCount(); | |
| 191 } | |
| 192 // Assign global indices to the new suggestions. | |
| 193 for (SnippetArticle suggestion : suggestions) { | |
| 194 suggestion.mGlobalPosition = globalPositionOffset + suggestion.mPosi tion; | |
| 195 } | |
| 196 | |
| 197 mSections.get(category).setSuggestions(suggestions, status, replaceExist ing); | 191 mSections.get(category).setSuggestions(suggestions, status, replaceExist ing); |
| 198 } | 192 } |
| 199 | 193 |
| 200 private boolean canLoadSuggestions(@CategoryInt int category, @CategoryStatu sEnum int status) { | 194 private boolean canLoadSuggestions(@CategoryInt int category, @CategoryStatu sEnum int status) { |
| 201 // We never want to add suggestions from unknown categories. | 195 // We never want to add suggestions from unknown categories. |
| 202 if (!mSections.containsKey(category)) return false; | 196 if (!mSections.containsKey(category)) return false; |
| 203 | 197 |
| 204 // The status may have changed while the suggestions were loading, perha ps they should not | 198 // The status may have changed while the suggestions were loading, perha ps they should not |
| 205 // be displayed any more. | 199 // be displayed any more. |
| 206 if (!SnippetsBridge.isCategoryEnabled(status)) { | 200 if (!SnippetsBridge.isCategoryEnabled(status)) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 247 /** | 241 /** |
| 248 * @return Whether the list of sections is empty. | 242 * @return Whether the list of sections is empty. |
| 249 */ | 243 */ |
| 250 public boolean isEmpty() { | 244 public boolean isEmpty() { |
| 251 return mSections.isEmpty(); | 245 return mSections.isEmpty(); |
| 252 } | 246 } |
| 253 | 247 |
| 254 SuggestionsSection getSectionForTesting(@CategoryInt int categoryId) { | 248 SuggestionsSection getSectionForTesting(@CategoryInt int categoryId) { |
| 255 return mSections.get(categoryId); | 249 return mSections.get(categoryId); |
| 256 } | 250 } |
| 251 | |
| 252 /** | |
| 253 * Attributes ranks to suggestions and related elements. | |
| 254 * | |
| 255 * Ranks here are 0-based scores attributed based on the position or loading order of the | |
| 256 * elements. See implementation for more details. | |
| 257 */ | |
| 258 public static class SuggestionRanker { | |
|
Bernhard Bauer
2017/01/17 17:42:31
Can we move this to a separate class? There isn't
dgn
2017/01/17 18:46:24
Done.
| |
| 259 private final Map<Integer, Integer> mSuggestionsAddedPerSection = new Li nkedHashMap<>(); | |
| 260 private int mTotalAddedSuggestions; | |
| 261 | |
| 262 /** | |
| 263 * Attributes a per section rank to the provided action item. | |
| 264 * @see ActionItem#getPerSectionRank() | |
| 265 */ | |
| 266 public void rankItem(ActionItem actionItem, SuggestionsSection section) { | |
|
Bernhard Bauer
2017/01/17 17:42:31
Can we rename these methods to rankActionItem() an
dgn
2017/01/17 18:46:24
Done.
| |
| 267 if (actionItem.getPerSectionRank() != -1) return; // Item was alread y ranked. | |
| 268 actionItem.setRank(section.getSuggestionsCount()); | |
| 269 } | |
| 270 | |
| 271 /** | |
| 272 * Attributes global and per section rank to the provided suggestion. | |
| 273 * @see SnippetArticle#getPerSectionRank() | |
| 274 * @see SnippetArticle#getGlobalRank() | |
| 275 */ | |
| 276 public void rankItem(SnippetArticle suggestion) { | |
| 277 int globalRank = mTotalAddedSuggestions++; | |
| 278 int perSectionRank = mSuggestionsAddedPerSection.get(suggestion.mCat egory); | |
| 279 mSuggestionsAddedPerSection.put(suggestion.mCategory, perSectionRank + 1); | |
| 280 | |
| 281 suggestion.setRank(perSectionRank, globalRank); | |
| 282 } | |
| 283 | |
| 284 public void registerCategory(@CategoryInt int category) { | |
| 285 mSuggestionsAddedPerSection.put(category, 0); | |
| 286 } | |
| 287 } | |
| 257 } | 288 } |
| OLD | NEW |