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; | 5 package org.chromium.chrome.browser.ntp; |
6 | 6 |
7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
8 import android.content.Context; | 8 import android.content.Context; |
9 import android.graphics.Canvas; | 9 import android.graphics.Canvas; |
10 import android.graphics.Point; | 10 import android.graphics.Point; |
11 import android.graphics.Rect; | 11 import android.graphics.Rect; |
12 import android.net.Uri; | |
13 import android.os.Build; | 12 import android.os.Build; |
14 import android.os.SystemClock; | |
15 import android.support.v4.view.ViewCompat; | 13 import android.support.v4.view.ViewCompat; |
16 import android.support.v7.widget.RecyclerView; | 14 import android.support.v7.widget.RecyclerView; |
17 import android.text.TextUtils; | 15 import android.text.TextUtils; |
18 import android.view.LayoutInflater; | 16 import android.view.LayoutInflater; |
19 import android.view.View; | 17 import android.view.View; |
20 | 18 |
21 import org.chromium.base.ApiCompatibilityUtils; | 19 import org.chromium.base.ApiCompatibilityUtils; |
22 import org.chromium.base.Callback; | |
23 import org.chromium.base.CommandLine; | 20 import org.chromium.base.CommandLine; |
24 import org.chromium.base.ContextUtils; | 21 import org.chromium.base.ContextUtils; |
25 import org.chromium.base.Log; | 22 import org.chromium.base.Log; |
26 import org.chromium.base.ObserverList; | |
27 import org.chromium.base.ThreadUtils; | |
28 import org.chromium.base.VisibleForTesting; | 23 import org.chromium.base.VisibleForTesting; |
29 import org.chromium.base.metrics.RecordHistogram; | 24 import org.chromium.base.metrics.RecordHistogram; |
30 import org.chromium.base.metrics.RecordUserAction; | 25 import org.chromium.base.metrics.RecordUserAction; |
31 import org.chromium.chrome.R; | 26 import org.chromium.chrome.R; |
32 import org.chromium.chrome.browser.ChromeActivity; | 27 import org.chromium.chrome.browser.ChromeActivity; |
33 import org.chromium.chrome.browser.ChromeFeatureList; | 28 import org.chromium.chrome.browser.ChromeFeatureList; |
34 import org.chromium.chrome.browser.ChromeSwitches; | 29 import org.chromium.chrome.browser.ChromeSwitches; |
35 import org.chromium.chrome.browser.NativePage; | 30 import org.chromium.chrome.browser.NativePage; |
36 import org.chromium.chrome.browser.UrlConstants; | 31 import org.chromium.chrome.browser.UrlConstants; |
37 import org.chromium.chrome.browser.bookmarks.BookmarkUtils; | |
38 import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareT humbnailProvider; | 32 import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareT humbnailProvider; |
39 import org.chromium.chrome.browser.download.DownloadManagerService; | 33 import org.chromium.chrome.browser.download.DownloadManagerService; |
40 import org.chromium.chrome.browser.download.DownloadUtils; | |
41 import org.chromium.chrome.browser.favicon.FaviconHelper; | 34 import org.chromium.chrome.browser.favicon.FaviconHelper; |
42 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback; | |
43 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallbac k; | |
44 import org.chromium.chrome.browser.favicon.LargeIconBridge; | 35 import org.chromium.chrome.browser.favicon.LargeIconBridge; |
45 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback; | |
46 import org.chromium.chrome.browser.metrics.StartupMetrics; | 36 import org.chromium.chrome.browser.metrics.StartupMetrics; |
47 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; | |
48 import org.chromium.chrome.browser.ntp.LogoBridge.Logo; | 37 import org.chromium.chrome.browser.ntp.LogoBridge.Logo; |
49 import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver; | 38 import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver; |
50 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; | 39 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; |
51 import org.chromium.chrome.browser.ntp.snippets.KnownCategories; | |
52 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; | |
53 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; | 40 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; |
54 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig; | 41 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig; |
55 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; | 42 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; |
56 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; | |
57 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; | |
58 import org.chromium.chrome.browser.preferences.PrefServiceBridge; | |
59 import org.chromium.chrome.browser.profiles.MostVisitedSites; | 43 import org.chromium.chrome.browser.profiles.MostVisitedSites; |
60 import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObse rver; | 44 import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObse rver; |
61 import org.chromium.chrome.browser.profiles.Profile; | 45 import org.chromium.chrome.browser.profiles.Profile; |
62 import org.chromium.chrome.browser.search_engines.TemplateUrlService; | 46 import org.chromium.chrome.browser.search_engines.TemplateUrlService; |
63 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl ServiceObserver; | 47 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl ServiceObserver; |
64 import org.chromium.chrome.browser.snackbar.Snackbar; | 48 import org.chromium.chrome.browser.snackbar.Snackbar; |
65 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; | 49 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; |
66 import org.chromium.chrome.browser.suggestions.SuggestionsMetricsReporter; | 50 import org.chromium.chrome.browser.suggestions.SuggestionsMetricsReporter; |
51 import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate; | |
52 import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegateImpl ; | |
53 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegateImpl; | |
67 import org.chromium.chrome.browser.sync.SyncSessionsMetrics; | 54 import org.chromium.chrome.browser.sync.SyncSessionsMetrics; |
68 import org.chromium.chrome.browser.tab.EmptyTabObserver; | 55 import org.chromium.chrome.browser.tab.EmptyTabObserver; |
69 import org.chromium.chrome.browser.tab.Tab; | 56 import org.chromium.chrome.browser.tab.Tab; |
70 import org.chromium.chrome.browser.tab.TabObserver; | 57 import org.chromium.chrome.browser.tab.TabObserver; |
71 import org.chromium.chrome.browser.tabmodel.TabModel; | 58 import org.chromium.chrome.browser.tabmodel.TabModel; |
72 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; | |
73 import org.chromium.chrome.browser.tabmodel.TabModelSelector; | 59 import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
74 import org.chromium.chrome.browser.tabmodel.TabModelUtils; | 60 import org.chromium.chrome.browser.tabmodel.TabModelUtils; |
75 import org.chromium.chrome.browser.tabmodel.document.TabDelegate; | |
76 import org.chromium.chrome.browser.util.UrlUtilities; | 61 import org.chromium.chrome.browser.util.UrlUtilities; |
77 import org.chromium.content_public.browser.LoadUrlParams; | 62 import org.chromium.content_public.browser.LoadUrlParams; |
78 import org.chromium.content_public.browser.NavigationController; | 63 import org.chromium.content_public.browser.NavigationController; |
79 import org.chromium.content_public.browser.NavigationEntry; | 64 import org.chromium.content_public.browser.NavigationEntry; |
80 import org.chromium.content_public.common.Referrer; | |
81 import org.chromium.net.NetworkChangeNotifier; | 65 import org.chromium.net.NetworkChangeNotifier; |
82 import org.chromium.ui.base.DeviceFormFactor; | 66 import org.chromium.ui.base.DeviceFormFactor; |
83 import org.chromium.ui.base.PageTransition; | 67 import org.chromium.ui.base.PageTransition; |
84 import org.chromium.ui.mojom.WindowOpenDisposition; | 68 import org.chromium.ui.mojom.WindowOpenDisposition; |
85 | 69 |
86 import java.util.HashSet; | |
87 import java.util.Set; | |
88 import java.util.concurrent.TimeUnit; | 70 import java.util.concurrent.TimeUnit; |
89 | 71 |
90 import jp.tomorrowkey.android.gifplayer.BaseGifImage; | 72 import jp.tomorrowkey.android.gifplayer.BaseGifImage; |
91 | 73 |
92 /** | 74 /** |
93 * Provides functionality when the user interacts with the NTP. | 75 * Provides functionality when the user interacts with the NTP. |
94 */ | 76 */ |
95 public class NewTabPage | 77 public class NewTabPage |
96 implements NativePage, InvalidationAwareThumbnailProvider, TemplateUrlSe rviceObserver { | 78 implements NativePage, InvalidationAwareThumbnailProvider, TemplateUrlSe rviceObserver { |
97 private static final String TAG = "NewTabPage"; | 79 private static final String TAG = "NewTabPage"; |
98 | 80 |
99 // UMA enum constants. CTA means the "click-to-action" icon. | 81 // UMA enum constants. CTA means the "click-to-action" icon. |
100 private static final String LOGO_SHOWN_UMA_NAME = "NewTabPage.LogoShown"; | 82 private static final String LOGO_SHOWN_UMA_NAME = "NewTabPage.LogoShown"; |
101 private static final int STATIC_LOGO_SHOWN = 0; | 83 private static final int STATIC_LOGO_SHOWN = 0; |
102 private static final int CTA_IMAGE_SHOWN = 1; | 84 private static final int CTA_IMAGE_SHOWN = 1; |
103 | 85 |
104 private static final String LOGO_CLICK_UMA_NAME = "NewTabPage.LogoClick"; | 86 private static final String LOGO_CLICK_UMA_NAME = "NewTabPage.LogoClick"; |
105 private static final int STATIC_LOGO_CLICKED = 0; | 87 private static final int STATIC_LOGO_CLICKED = 0; |
106 private static final int CTA_IMAGE_CLICKED = 1; | 88 private static final int CTA_IMAGE_CLICKED = 1; |
107 private static final int ANIMATED_LOGO_CLICKED = 2; | 89 private static final int ANIMATED_LOGO_CLICKED = 2; |
108 | 90 |
109 // Key for the scroll position data that may be stored in a navigation entry . | 91 // Key for the scroll position data that may be stored in a navigation entry . |
110 private static final String NAVIGATION_ENTRY_SCROLL_POSITION_KEY = "NewTabPa geScrollPosition"; | 92 private static final String NAVIGATION_ENTRY_SCROLL_POSITION_KEY = "NewTabPa geScrollPosition"; |
111 | 93 |
112 private static final String CHROME_CONTENT_SUGGESTIONS_REFERRER = | |
113 "https://www.googleapis.com/auth/chrome-content-suggestions"; | |
114 | |
115 private static MostVisitedSites sMostVisitedSitesForTests; | 94 private static MostVisitedSites sMostVisitedSitesForTests; |
116 private static SuggestionsSource sSuggestionsSourceForTests; | 95 private static SuggestionsSource sSuggestionsSourceForTests; |
117 | 96 |
118 private final Tab mTab; | 97 private final Tab mTab; |
119 private final TabModelSelector mTabModelSelector; | 98 private final TabModelSelector mTabModelSelector; |
120 private final ChromeActivity mActivity; | 99 private final ChromeActivity mActivity; |
121 | 100 |
122 private final Profile mProfile; | |
123 private final String mTitle; | 101 private final String mTitle; |
124 private final int mBackgroundColor; | 102 private final int mBackgroundColor; |
125 private final int mThemeColor; | 103 private final int mThemeColor; |
126 private final NewTabPageView mNewTabPageView; | 104 private final NewTabPageView mNewTabPageView; |
105 private final NewTabPageManagerImpl mNewTabPageManager; | |
127 | 106 |
128 private TabObserver mTabObserver; | 107 private TabObserver mTabObserver; |
129 private MostVisitedSites mMostVisitedSites; | 108 private MostVisitedSites mMostVisitedSites; |
130 private SnackbarController mMostVisitedItemRemovedController; | 109 private SnackbarController mMostVisitedItemRemovedController; |
131 private FaviconHelper mFaviconHelper; | 110 private FaviconHelper mFaviconHelper; |
132 private LargeIconBridge mLargeIconBridge; | 111 private LargeIconBridge mLargeIconBridge; |
Michael van Ouwerkerk
2017/01/18 14:02:44
This is now unused, it should be deleted from NewT
dgn
2017/01/18 16:22:27
Done.
| |
133 private LogoBridge mLogoBridge; | 112 private LogoBridge mLogoBridge; |
134 private boolean mSearchProviderHasLogo; | 113 private boolean mSearchProviderHasLogo; |
135 private String mOnLogoClickUrl; | 114 private String mOnLogoClickUrl; |
136 private String mAnimatedLogoUrl; | 115 private String mAnimatedLogoUrl; |
137 private FakeboxDelegate mFakeboxDelegate; | 116 private FakeboxDelegate mFakeboxDelegate; |
138 private SnippetsBridge mSnippetsBridge; | 117 private SnippetsBridge mSnippetsBridge; |
139 | 118 |
140 // The timestamp at which the constructor was called. | 119 // The timestamp at which the constructor was called. |
141 private final long mConstructedTimeNs; | 120 private final long mConstructedTimeNs; |
142 | 121 |
143 // The timestamp at which this NTP was last shown to the user. | 122 // The timestamp at which this NTP was last shown to the user. |
144 private long mLastShownTimeNs; | 123 private long mLastShownTimeNs; |
145 | 124 |
146 private boolean mIsLoaded; | 125 private boolean mIsLoaded; |
147 | 126 |
148 // Whether destroy() has been called. | 127 // Whether destroy() has been called. |
149 private boolean mIsDestroyed; | 128 private boolean mIsDestroyed; |
150 | 129 |
151 private final ObserverList<DestructionObserver> mDestructionObservers = new ObserverList<>(); | |
152 | |
153 /** | 130 /** |
154 * Allows clients to listen for updates to the scroll changes of the search box on the | 131 * Allows clients to listen for updates to the scroll changes of the search box on the |
155 * NTP. | 132 * NTP. |
156 */ | 133 */ |
157 public interface OnSearchBoxScrollListener { | 134 public interface OnSearchBoxScrollListener { |
158 /** | 135 /** |
159 * Callback to be notified when the scroll position of the search box on the NTP has | 136 * Callback to be notified when the scroll position of the search box on the NTP has |
160 * changed. A scroll percentage of 0, means the search box has no scrol l applied and | 137 * changed. A scroll percentage of 0, means the search box has no scrol l applied and |
161 * is in it's natural resting position. A value of 1 means the search b ox is scrolled | 138 * is in it's natural resting position. A value of 1 means the search b ox is scrolled |
162 * entirely to the top of the screen viewport. | 139 * entirely to the top of the screen viewport. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
221 @VisibleForTesting | 198 @VisibleForTesting |
222 public static void setMostVisitedSitesForTests(MostVisitedSites mostVisitedS itesForTests) { | 199 public static void setMostVisitedSitesForTests(MostVisitedSites mostVisitedS itesForTests) { |
223 sMostVisitedSitesForTests = mostVisitedSitesForTests; | 200 sMostVisitedSitesForTests = mostVisitedSitesForTests; |
224 } | 201 } |
225 | 202 |
226 @VisibleForTesting | 203 @VisibleForTesting |
227 public static void setSuggestionsSourceForTests(SuggestionsSource suggestion sSource) { | 204 public static void setSuggestionsSourceForTests(SuggestionsSource suggestion sSource) { |
228 sSuggestionsSourceForTests = suggestionsSource; | 205 sSuggestionsSourceForTests = suggestionsSource; |
229 } | 206 } |
230 | 207 |
231 private final NewTabPageManager mNewTabPageManager = new NewTabPageManager() { | 208 private class NewTabPageManagerImpl |
232 private static final String NTP_OFFLINE_PAGES_FEATURE_NAME = "NTPOffline Pages"; | 209 extends SuggestionsUiDelegateImpl implements NewTabPageManager { |
210 public NewTabPageManagerImpl(SuggestionsSource suggestionsSource, | |
211 SuggestionsMetricsReporter metricsReporter, | |
212 SuggestionsNavigationDelegate navigationDelegate, Profile profil e, Tab currentTab) { | |
213 super(suggestionsSource, metricsReporter, navigationDelegate, profil e, currentTab); | |
214 } | |
233 | 215 |
234 private boolean isNtpOfflinePagesEnabled() { | 216 private boolean isNtpOfflinePagesEnabled() { |
235 return ChromeFeatureList.isEnabled(NTP_OFFLINE_PAGES_FEATURE_NAME); | 217 return ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_OFFLINE_PAG ES_FEATURE_NAME); |
236 } | 218 } |
237 | 219 |
238 @Override | 220 @Override |
239 public boolean isLocationBarShownInNTP() { | 221 public boolean isLocationBarShownInNTP() { |
240 if (mIsDestroyed) return false; | 222 if (mIsDestroyed) return false; |
241 Context context = mNewTabPageView.getContext(); | 223 Context context = mNewTabPageView.getContext(); |
242 return isInSingleUrlBarMode(context) | 224 return isInSingleUrlBarMode(context) |
243 && !mNewTabPageView.urlFocusAnimationsDisabled(); | 225 && !mNewTabPageView.urlFocusAnimationsDisabled(); |
244 } | 226 } |
245 | 227 |
(...skipping 28 matching lines...) Expand all Loading... | |
274 // TODO(treib): Should we call recordOpenedMostVisitedItem here? | 256 // TODO(treib): Should we call recordOpenedMostVisitedItem here? |
275 if (windowDisposition != WindowOpenDisposition.NEW_WINDOW) { | 257 if (windowDisposition != WindowOpenDisposition.NEW_WINDOW) { |
276 recordOpenedMostVisitedItem(item); | 258 recordOpenedMostVisitedItem(item); |
277 } | 259 } |
278 | 260 |
279 if (windowDisposition == WindowOpenDisposition.CURRENT_TAB | 261 if (windowDisposition == WindowOpenDisposition.CURRENT_TAB |
280 && switchToExistingTab(url)) { | 262 && switchToExistingTab(url)) { |
281 return; | 263 return; |
282 } | 264 } |
283 | 265 |
284 openUrl(windowDisposition, new LoadUrlParams(url, PageTransition.AUT O_BOOKMARK)); | 266 getNavigationDelegate().openUrl( |
267 windowDisposition, new LoadUrlParams(url, PageTransition.AUT O_BOOKMARK)); | |
285 } | 268 } |
286 | 269 |
287 @Override | 270 @Override |
288 public void removeMostVisitedItem(MostVisitedItem item) { | 271 public void removeMostVisitedItem(MostVisitedItem item) { |
289 mMostVisitedSites.addBlacklistedUrl(item.getUrl()); | 272 mMostVisitedSites.addBlacklistedUrl(item.getUrl()); |
290 showMostVisitedItemRemovedSnackbar(item.getUrl()); | 273 showMostVisitedItemRemovedSnackbar(item.getUrl()); |
291 } | 274 } |
292 | 275 |
293 @Override | |
294 public void onLearnMoreClicked() { | |
295 if (mIsDestroyed) return; | |
296 NewTabPageUma.recordAction(NewTabPageUma.ACTION_CLICKED_LEARN_MORE); | |
297 String url = "https://support.google.com/chrome/?p=new_tab"; | |
298 // TODO(mastiz): Change this to LINK? | |
299 openUrl(WindowOpenDisposition.CURRENT_TAB, | |
300 new LoadUrlParams(url, PageTransition.AUTO_BOOKMARK)); | |
301 } | |
302 | |
303 @TargetApi(Build.VERSION_CODES.LOLLIPOP) | 276 @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
304 private boolean switchToExistingTab(String url) { | 277 private boolean switchToExistingTab(String url) { |
305 String matchPattern = CommandLine.getInstance().getSwitchValue( | 278 String matchPattern = CommandLine.getInstance().getSwitchValue( |
306 ChromeSwitches.NTP_SWITCH_TO_EXISTING_TAB); | 279 ChromeSwitches.NTP_SWITCH_TO_EXISTING_TAB); |
307 boolean matchByHost; | 280 boolean matchByHost; |
308 if ("url".equals(matchPattern)) { | 281 if ("url".equals(matchPattern)) { |
309 matchByHost = false; | 282 matchByHost = false; |
310 } else if ("host".equals(matchPattern)) { | 283 } else if ("host".equals(matchPattern)) { |
311 matchByHost = true; | 284 matchByHost = true; |
312 } else { | 285 } else { |
313 return false; | 286 return false; |
314 } | 287 } |
315 | 288 |
316 TabModel tabModel = mTabModelSelector.getModel(false); | 289 TabModel tabModel = mTabModelSelector.getModel(false); |
317 for (int i = tabModel.getCount() - 1; i >= 0; --i) { | 290 for (int i = tabModel.getCount() - 1; i >= 0; --i) { |
318 if (matchURLs(tabModel.getTabAt(i).getUrl(), url, matchByHost)) { | 291 if (matchURLs(tabModel.getTabAt(i).getUrl(), url, matchByHost)) { |
319 TabModelUtils.setIndex(tabModel, i); | 292 TabModelUtils.setIndex(tabModel, i); |
320 return true; | 293 return true; |
321 } | 294 } |
322 } | 295 } |
323 return false; | 296 return false; |
324 } | 297 } |
325 | 298 |
326 private boolean matchURLs(String url1, String url2, boolean matchByHost) { | 299 private boolean matchURLs(String url1, String url2, boolean matchByHost) { |
327 if (url1 == null || url2 == null) return false; | 300 if (url1 == null || url2 == null) return false; |
328 return matchByHost ? UrlUtilities.sameHost(url1, url2) : url1.equals (url2); | 301 return matchByHost ? UrlUtilities.sameHost(url1, url2) : url1.equals (url2); |
329 } | 302 } |
330 | 303 |
331 public SuggestionsMetricsReporter getSuggestionsMetricsReporter() { | |
332 return mSnippetsBridge; | |
333 } | |
334 | |
335 @Override | |
336 public void openSnippet(int windowOpenDisposition, SnippetArticle articl e) { | |
337 mSnippetsBridge.onSuggestionOpened(article, windowOpenDisposition); | |
338 NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_SNIPPET); | |
339 | |
340 if (article.mIsAssetDownload) { | |
341 assert windowOpenDisposition == WindowOpenDisposition.CURRENT_TA B | |
342 || windowOpenDisposition == WindowOpenDisposition.NEW_WI NDOW | |
343 || windowOpenDisposition == WindowOpenDisposition.NEW_FO REGROUND_TAB; | |
344 DownloadUtils.openFile( | |
345 article.getAssetDownloadFile(), article.getAssetDownload MimeType(), false); | |
346 return; | |
347 } | |
348 | |
349 if (article.isRecentTab()) { | |
350 assert windowOpenDisposition == WindowOpenDisposition.CURRENT_TA B; | |
351 // TODO(vitaliii): Add a debug check that the result is true aft er crbug.com/662924 | |
352 // is resolved. | |
353 openRecentTabSnippet(article); | |
354 return; | |
355 } | |
356 | |
357 // TODO(treib): Also track other dispositions. crbug.com/665915 | |
358 if (windowOpenDisposition == WindowOpenDisposition.CURRENT_TAB) { | |
359 NewTabPageUma.monitorContentSuggestionVisit(mTab, article.mCateg ory); | |
360 } | |
361 | |
362 LoadUrlParams loadUrlParams; | |
363 // We explicitly open an offline page only for offline page download s. For all other | |
364 // sections the URL is opened and it is up to Offline Pages whether to open its offline | |
365 // page (e.g. when offline). | |
366 if (article.isDownload() && !article.mIsAssetDownload) { | |
367 assert article.getOfflinePageOfflineId() != null; | |
368 assert windowOpenDisposition == WindowOpenDisposition.CURRENT_TA B | |
369 || windowOpenDisposition == WindowOpenDisposition.NEW_WI NDOW | |
370 || windowOpenDisposition == WindowOpenDisposition.NEW_FO REGROUND_TAB; | |
371 loadUrlParams = OfflinePageUtils.getLoadUrlParamsForOpeningOffli neVersion( | |
372 article.mUrl, article.getOfflinePageOfflineId()); | |
373 // Extra headers are not read in loadUrl, but verbatim headers a re. | |
374 loadUrlParams.setVerbatimHeaders(loadUrlParams.getExtraHeadersSt ring()); | |
375 } else { | |
376 loadUrlParams = new LoadUrlParams(article.mUrl, PageTransition.A UTO_BOOKMARK); | |
377 } | |
378 | |
379 // For article suggestions, we set the referrer. This is exploited | |
380 // to filter out these history entries for NTP tiles. | |
381 // TODO(mastiz): Extend this with support for other categories. | |
382 if (article.mCategory == KnownCategories.ARTICLES) { | |
383 loadUrlParams.setReferrer(new Referrer( | |
384 CHROME_CONTENT_SUGGESTIONS_REFERRER, Referrer.REFERRER_P OLICY_ALWAYS)); | |
385 } | |
386 | |
387 openUrl(windowOpenDisposition, loadUrlParams); | |
388 } | |
389 | |
390 private boolean openRecentTabSnippet(SnippetArticle recentTabArticle) { | |
391 TabModel tabModel = mTabModelSelector.getModel(false); | |
392 int tabId = Integer.parseInt(recentTabArticle.getRecentTabId()); | |
393 int tabIndex = TabModelUtils.getTabIndexById(tabModel, tabId); | |
394 if (tabIndex == TabModel.INVALID_TAB_INDEX) return false; | |
395 TabModelUtils.setIndex(tabModel, tabIndex); | |
396 return true; | |
397 } | |
398 | |
399 private void openUrl(int windowOpenDisposition, LoadUrlParams loadUrlPar ams) { | |
400 assert !mIsDestroyed; | |
401 switch (windowOpenDisposition) { | |
402 case WindowOpenDisposition.CURRENT_TAB: | |
403 mTab.loadUrl(loadUrlParams); | |
404 break; | |
405 case WindowOpenDisposition.NEW_FOREGROUND_TAB: | |
406 openUrlInNewTab(loadUrlParams, false); | |
407 break; | |
408 case WindowOpenDisposition.OFF_THE_RECORD: | |
409 openUrlInNewTab(loadUrlParams, true); | |
410 break; | |
411 case WindowOpenDisposition.NEW_WINDOW: | |
412 openUrlInNewWindow(loadUrlParams); | |
413 break; | |
414 case WindowOpenDisposition.SAVE_TO_DISK: | |
415 saveUrlForOffline(loadUrlParams.getUrl()); | |
416 break; | |
417 default: | |
418 assert false; | |
419 } | |
420 } | |
421 | |
422 @Override | |
423 public boolean isOpenInNewWindowEnabled() { | |
424 return MultiWindowUtils.getInstance().isOpenInOtherWindowSupported(m Activity); | |
425 } | |
426 | |
427 @Override | |
428 public boolean isOpenInIncognitoEnabled() { | |
429 return PrefServiceBridge.getInstance().isIncognitoModeEnabled(); | |
430 } | |
431 | |
432 private void openUrlInNewWindow(LoadUrlParams loadUrlParams) { | |
433 TabDelegate tabDelegate = new TabDelegate(false); | |
434 tabDelegate.createTabInOtherWindow(loadUrlParams, mActivity, mTab.ge tParentId()); | |
435 } | |
436 | |
437 private void openUrlInNewTab(LoadUrlParams loadUrlParams, boolean incogn ito) { | |
438 mTabModelSelector.openNewTab( | |
439 loadUrlParams, TabLaunchType.FROM_LONGPRESS_BACKGROUND, mTab , incognito); | |
440 } | |
441 | |
442 private void saveUrlForOffline(String url) { | |
443 OfflinePageBridge.getForProfile(mProfile) | |
444 .savePageLater(url, "ntp_suggestions", true /* userRequested */); | |
445 } | |
446 | |
447 @Override | |
448 public void navigateToBookmarks() { | |
449 if (mIsDestroyed) return; | |
450 RecordUserAction.record("MobileNTPSwitchToBookmarks"); | |
451 BookmarkUtils.showBookmarkManager(mActivity); | |
452 } | |
453 | |
454 @Override | |
455 public void navigateToRecentTabs() { | |
456 if (mIsDestroyed) return; | |
457 RecordUserAction.record("MobileNTPSwitchToOpenTabs"); | |
458 mTab.loadUrl(new LoadUrlParams(UrlConstants.RECENT_TABS_URL)); | |
459 } | |
460 | |
461 @Override | |
462 public void navigateToDownloadManager() { | |
463 if (mIsDestroyed) return; | |
464 assert DownloadUtils.isDownloadHomeEnabled(); | |
465 RecordUserAction.record("MobileNTPSwitchToDownloadManager"); | |
466 DownloadUtils.showDownloadManager(mActivity, mTab); | |
467 } | |
468 | |
469 @Override | 304 @Override |
470 public void focusSearchBox(boolean beginVoiceSearch, String pastedText) { | 305 public void focusSearchBox(boolean beginVoiceSearch, String pastedText) { |
471 if (mIsDestroyed) return; | 306 if (mIsDestroyed) return; |
472 if (mFakeboxDelegate != null) { | 307 if (mFakeboxDelegate != null) { |
473 if (beginVoiceSearch) { | 308 if (beginVoiceSearch) { |
474 mFakeboxDelegate.startVoiceRecognition(); | 309 mFakeboxDelegate.startVoiceRecognition(); |
475 } else { | 310 } else { |
476 mFakeboxDelegate.requestUrlFocusFromFakebox(pastedText); | 311 mFakeboxDelegate.requestUrlFocusFromFakebox(pastedText); |
477 } | 312 } |
478 } | 313 } |
479 } | 314 } |
480 | 315 |
481 @Override | 316 @Override |
482 public void setMostVisitedURLsObserver(MostVisitedURLsObserver observer, int numResults) { | 317 public void setMostVisitedURLsObserver(MostVisitedURLsObserver observer, int numResults) { |
483 if (mIsDestroyed) return; | 318 if (mIsDestroyed) return; |
484 mMostVisitedSites.setMostVisitedURLsObserver(observer, numResults); | 319 mMostVisitedSites.setMostVisitedURLsObserver(observer, numResults); |
485 } | 320 } |
486 | 321 |
487 @Override | 322 @Override |
488 public void getLocalFaviconImageForURL( | |
489 String url, int size, FaviconImageCallback faviconCallback) { | |
490 if (mIsDestroyed) return; | |
491 if (mFaviconHelper == null) mFaviconHelper = new FaviconHelper(); | |
492 mFaviconHelper.getLocalFaviconImageForURL(mProfile, url, size, favic onCallback); | |
493 } | |
494 | |
495 @Override | |
496 public void getLargeIconForUrl(String url, int size, LargeIconCallback c allback) { | |
497 if (mIsDestroyed) return; | |
498 if (mLargeIconBridge == null) mLargeIconBridge = new LargeIconBridge (mProfile); | |
499 mLargeIconBridge.getLargeIconForUrl(url, size, callback); | |
500 } | |
501 | |
502 @Override | |
503 public void ensureIconIsAvailable(String pageUrl, String iconUrl, boolea n isLargeIcon, | |
504 boolean isTemporary, IconAvailabilityCallback callback) { | |
505 if (mIsDestroyed) return; | |
506 if (mFaviconHelper == null) mFaviconHelper = new FaviconHelper(); | |
507 mFaviconHelper.ensureIconIsAvailable(mProfile, mTab.getWebContents() , pageUrl, iconUrl, | |
508 isLargeIcon, isTemporary, callback); | |
509 } | |
510 | |
511 private boolean isLocalUrl(String url) { | |
512 return "file".equals(Uri.parse(url).getScheme()); | |
513 } | |
514 | |
515 @Override | |
516 public void getUrlsAvailableOffline( | |
517 Set<String> pageUrls, final Callback<Set<String>> callback) { | |
518 final Set<String> urlsAvailableOffline = new HashSet<>(); | |
519 if (mIsDestroyed || !isNtpOfflinePagesEnabled()) { | |
520 callback.onResult(urlsAvailableOffline); | |
521 return; | |
522 } | |
523 | |
524 HashSet<String> urlsToCheckForOfflinePage = new HashSet<>(); | |
525 | |
526 for (String pageUrl : pageUrls) { | |
527 if (isLocalUrl(pageUrl)) { | |
528 urlsAvailableOffline.add(pageUrl); | |
529 } else { | |
530 urlsToCheckForOfflinePage.add(pageUrl); | |
531 } | |
532 } | |
533 | |
534 final long offlineQueryStartTime = SystemClock.elapsedRealtime(); | |
535 | |
536 OfflinePageBridge offlinePageBridge = OfflinePageBridge.getForProfil e(mProfile); | |
537 | |
538 // TODO(dewittj): Remove this code by making the NTP badging availab le after the NTP is | |
539 // fully loaded. | |
540 if (offlinePageBridge == null || !offlinePageBridge.isOfflinePageMod elLoaded()) { | |
541 // Posting a task to avoid potential re-entrancy issues. | |
542 ThreadUtils.postOnUiThread(new Runnable() { | |
543 @Override | |
544 public void run() { | |
545 callback.onResult(urlsAvailableOffline); | |
546 } | |
547 }); | |
548 return; | |
549 } | |
550 | |
551 offlinePageBridge.checkPagesExistOffline( | |
552 urlsToCheckForOfflinePage, new Callback<Set<String>>() { | |
553 @Override | |
554 public void onResult(Set<String> urlsWithOfflinePages) { | |
555 urlsAvailableOffline.addAll(urlsWithOfflinePages); | |
556 callback.onResult(urlsAvailableOffline); | |
557 RecordHistogram.recordTimesHistogram("NewTabPage.Off lineUrlsLoadTime", | |
558 SystemClock.elapsedRealtime() - offlineQuery StartTime, | |
559 TimeUnit.MILLISECONDS); | |
560 } | |
561 }); | |
562 } | |
563 | |
564 @Override | |
565 public void onLogoClicked(boolean isAnimatedLogoShowing) { | 323 public void onLogoClicked(boolean isAnimatedLogoShowing) { |
566 if (mIsDestroyed) return; | 324 if (mIsDestroyed) return; |
567 | 325 |
568 if (!isAnimatedLogoShowing && mAnimatedLogoUrl != null) { | 326 if (!isAnimatedLogoShowing && mAnimatedLogoUrl != null) { |
569 RecordHistogram.recordSparseSlowlyHistogram(LOGO_CLICK_UMA_NAME, CTA_IMAGE_CLICKED); | 327 RecordHistogram.recordSparseSlowlyHistogram(LOGO_CLICK_UMA_NAME, CTA_IMAGE_CLICKED); |
570 mNewTabPageView.showLogoLoadingView(); | 328 mNewTabPageView.showLogoLoadingView(); |
571 mLogoBridge.getAnimatedLogo(new LogoBridge.AnimatedLogoCallback( ) { | 329 mLogoBridge.getAnimatedLogo(new LogoBridge.AnimatedLogoCallback( ) { |
572 @Override | 330 @Override |
573 public void onAnimatedLogoAvailable(BaseGifImage animatedLog oImage) { | 331 public void onAnimatedLogoAvailable(BaseGifImage animatedLog oImage) { |
574 if (mIsDestroyed) return; | 332 if (mIsDestroyed) return; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
638 SyncSessionsMetrics.recordYoungestForeignTabAgeOnNTP(); | 396 SyncSessionsMetrics.recordYoungestForeignTabAgeOnNTP(); |
639 } | 397 } |
640 | 398 |
641 @Override | 399 @Override |
642 public SuggestionsSource getSuggestionsSource() { | 400 public SuggestionsSource getSuggestionsSource() { |
643 if (sSuggestionsSourceForTests != null) return sSuggestionsSourceFor Tests; | 401 if (sSuggestionsSourceForTests != null) return sSuggestionsSourceFor Tests; |
644 return mSnippetsBridge; | 402 return mSnippetsBridge; |
645 } | 403 } |
646 | 404 |
647 @Override | 405 @Override |
648 public void addDestructionObserver(DestructionObserver destructionObserv er) { | |
649 if (mIsDestroyed) return; | |
650 mDestructionObservers.addObserver(destructionObserver); | |
651 } | |
652 | |
653 @Override | |
654 public boolean isCurrentPage() { | 406 public boolean isCurrentPage() { |
655 if (mIsDestroyed) return false; | 407 if (mIsDestroyed) return false; |
656 if (mFakeboxDelegate == null) return false; | 408 if (mFakeboxDelegate == null) return false; |
657 return mFakeboxDelegate.isCurrentPage(NewTabPage.this); | 409 return mFakeboxDelegate.isCurrentPage(NewTabPage.this); |
658 } | 410 } |
659 | 411 |
660 @Override | 412 @Override |
661 public ContextMenuManager getContextMenuManager() { | 413 public ContextMenuManager getContextMenuManager() { |
662 assert !mIsDestroyed; | 414 assert !mIsDestroyed; |
663 return mNewTabPageView.getContextMenuManager(); | 415 return mNewTabPageView.getContextMenuManager(); |
664 } | 416 } |
665 }; | 417 }; |
666 | 418 |
667 /** | 419 /** |
668 * Constructs a NewTabPage. | 420 * Constructs a NewTabPage. |
669 * @param activity The activity used for context to create the new tab page' s View. | 421 * @param activity The activity used for context to create the new tab page' s View. |
670 * @param tab The Tab that is showing this new tab page. | 422 * @param tab The Tab that is showing this new tab page. |
671 * @param tabModelSelector The TabModelSelector used to open tabs. | 423 * @param tabModelSelector The TabModelSelector used to open tabs. |
672 */ | 424 */ |
673 public NewTabPage(ChromeActivity activity, Tab tab, TabModelSelector tabMode lSelector) { | 425 public NewTabPage(ChromeActivity activity, Tab tab, TabModelSelector tabMode lSelector) { |
674 mConstructedTimeNs = System.nanoTime(); | 426 mConstructedTimeNs = System.nanoTime(); |
675 | 427 |
676 mTab = tab; | 428 mTab = tab; |
677 mActivity = activity; | 429 mActivity = activity; |
678 mTabModelSelector = tabModelSelector; | 430 mTabModelSelector = tabModelSelector; |
679 mProfile = tab.getProfile(); | 431 Profile profile = tab.getProfile(); |
432 | |
433 if (SnippetsConfig.isEnabled()) { | |
434 mSnippetsBridge = new SnippetsBridge(profile); | |
435 } | |
436 | |
437 SuggestionsNavigationDelegateImpl navigationDelegate = | |
Michael van Ouwerkerk
2017/01/16 15:31:15
Can this be of type SuggestionsNavigationDelegate?
| |
438 new SuggestionsNavigationDelegateImpl(mActivity, profile, tab, t abModelSelector); | |
439 mNewTabPageManager = new NewTabPageManagerImpl( | |
440 mSnippetsBridge, mSnippetsBridge, navigationDelegate, profile, t ab); | |
441 mNewTabPageManager.addDestructionObserver(navigationDelegate); | |
680 | 442 |
681 mTitle = activity.getResources().getString(R.string.button_new_tab); | 443 mTitle = activity.getResources().getString(R.string.button_new_tab); |
682 mBackgroundColor = ApiCompatibilityUtils.getColor(activity.getResources( ), R.color.ntp_bg); | 444 mBackgroundColor = ApiCompatibilityUtils.getColor(activity.getResources( ), R.color.ntp_bg); |
683 mThemeColor = ApiCompatibilityUtils.getColor( | 445 mThemeColor = ApiCompatibilityUtils.getColor( |
684 activity.getResources(), R.color.default_primary_color); | 446 activity.getResources(), R.color.default_primary_color); |
685 TemplateUrlService.getInstance().addObserver(this); | 447 TemplateUrlService.getInstance().addObserver(this); |
686 | 448 |
687 mTabObserver = new EmptyTabObserver() { | 449 mTabObserver = new EmptyTabObserver() { |
688 @Override | 450 @Override |
689 public void onShown(Tab tab) { | 451 public void onShown(Tab tab) { |
(...skipping 23 matching lines...) Expand all Loading... | |
713 // yet. This method will then be called a second time when the u ser navigates away, | 475 // yet. This method will then be called a second time when the u ser navigates away, |
714 // at which point the last committed entry is for the NTP. The e xtra data must only | 476 // at which point the last committed entry is for the NTP. The e xtra data must only |
715 // be set in the latter case. | 477 // be set in the latter case. |
716 if (!isNTPUrl(entry.getUrl())) return; | 478 if (!isNTPUrl(entry.getUrl())) return; |
717 | 479 |
718 controller.setEntryExtraData(index, NAVIGATION_ENTRY_SCROLL_POSI TION_KEY, | 480 controller.setEntryExtraData(index, NAVIGATION_ENTRY_SCROLL_POSI TION_KEY, |
719 Integer.toString(scrollPosition)); | 481 Integer.toString(scrollPosition)); |
720 } | 482 } |
721 }; | 483 }; |
722 mTab.addObserver(mTabObserver); | 484 mTab.addObserver(mTabObserver); |
723 mMostVisitedSites = buildMostVisitedSites(mProfile); | 485 mMostVisitedSites = buildMostVisitedSites(profile); |
724 mLogoBridge = new LogoBridge(mProfile); | 486 mLogoBridge = new LogoBridge(profile); |
725 updateSearchProviderHasLogo(); | 487 updateSearchProviderHasLogo(); |
726 | 488 |
727 if (SnippetsConfig.isEnabled()) { | |
728 mSnippetsBridge = new SnippetsBridge(mProfile); | |
729 } | |
730 | |
731 LayoutInflater inflater = LayoutInflater.from(activity); | 489 LayoutInflater inflater = LayoutInflater.from(activity); |
732 mNewTabPageView = (NewTabPageView) inflater.inflate(R.layout.new_tab_pag e_view, null); | 490 mNewTabPageView = (NewTabPageView) inflater.inflate(R.layout.new_tab_pag e_view, null); |
733 mNewTabPageView.initialize(mNewTabPageManager, mTab, mSearchProviderHasL ogo, | 491 mNewTabPageView.initialize(mNewTabPageManager, mTab, mSearchProviderHasL ogo, |
734 getScrollPositionFromNavigationEntry()); | 492 getScrollPositionFromNavigationEntry()); |
735 | 493 |
736 if (mSnippetsBridge != null) { | 494 if (mSnippetsBridge != null) { |
737 mSnippetsBridge.onNtpInitialized(); | 495 mSnippetsBridge.onNtpInitialized(); |
738 } | 496 } |
739 | 497 |
740 DownloadManagerService.getDownloadManagerService(ContextUtils.getApplica tionContext()) | 498 DownloadManagerService.getDownloadManagerService(ContextUtils.getApplica tionContext()) |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
960 mLogoBridge.destroy(); | 718 mLogoBridge.destroy(); |
961 mLogoBridge = null; | 719 mLogoBridge = null; |
962 } | 720 } |
963 if (mSnippetsBridge != null) { | 721 if (mSnippetsBridge != null) { |
964 mSnippetsBridge.destroy(); | 722 mSnippetsBridge.destroy(); |
965 mSnippetsBridge = null; | 723 mSnippetsBridge = null; |
966 } | 724 } |
967 if (mMostVisitedItemRemovedController != null) { | 725 if (mMostVisitedItemRemovedController != null) { |
968 mTab.getSnackbarManager().dismissSnackbars(mMostVisitedItemRemovedCo ntroller); | 726 mTab.getSnackbarManager().dismissSnackbars(mMostVisitedItemRemovedCo ntroller); |
969 } | 727 } |
970 for (DestructionObserver observer : mDestructionObservers) { | 728 mNewTabPageManager.onDestroy(); |
971 observer.onDestroy(); | |
972 } | |
973 mDestructionObservers.clear(); | |
974 TemplateUrlService.getInstance().removeObserver(this); | 729 TemplateUrlService.getInstance().removeObserver(this); |
975 mTab.removeObserver(mTabObserver); | 730 mTab.removeObserver(mTabObserver); |
976 mTabObserver = null; | 731 mTabObserver = null; |
977 mIsDestroyed = true; | 732 mIsDestroyed = true; |
978 } | 733 } |
979 | 734 |
980 @Override | 735 @Override |
981 public String getUrl() { | 736 public String getUrl() { |
982 return UrlConstants.NTP_URL; | 737 return UrlConstants.NTP_URL; |
983 } | 738 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1021 @Override | 776 @Override |
1022 public boolean shouldCaptureThumbnail() { | 777 public boolean shouldCaptureThumbnail() { |
1023 return mNewTabPageView.shouldCaptureThumbnail(); | 778 return mNewTabPageView.shouldCaptureThumbnail(); |
1024 } | 779 } |
1025 | 780 |
1026 @Override | 781 @Override |
1027 public void captureThumbnail(Canvas canvas) { | 782 public void captureThumbnail(Canvas canvas) { |
1028 mNewTabPageView.captureThumbnail(canvas); | 783 mNewTabPageView.captureThumbnail(canvas); |
1029 } | 784 } |
1030 } | 785 } |
OLD | NEW |