Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1229)

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPage.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPage.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPage.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecdb58617d327eb7c7e950fb77156bb5e9c28499
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -0,0 +1,488 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.ntp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.View;
+
+import com.google.android.apps.chrome.R;
+
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.browser.LogoBridge;
+import org.chromium.chrome.browser.LogoBridge.Logo;
+import org.chromium.chrome.browser.LogoBridge.LogoObserver;
+import org.chromium.chrome.browser.NativePage;
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.UrlConstants;
+import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider;
+import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils;
+import org.chromium.chrome.browser.favicon.FaviconHelper;
+import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
+import org.chromium.chrome.browser.favicon.LargeIconBridge;
+import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
+import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
+import org.chromium.chrome.browser.preferences.PrefServiceBridge;
+import org.chromium.chrome.browser.profiles.MostVisitedSites;
+import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObserver;
+import org.chromium.chrome.browser.profiles.MostVisitedSites.ThumbnailCallback;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.ui.base.PageTransition;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides functionality when the user interacts with the NTP.
+ */
+public class NewTabPage
+ implements NativePage, InvalidationAwareThumbnailProvider, TemplateUrlServiceObserver {
+
+ // MostVisitedItem Context menu item IDs.
+ static final int ID_OPEN_IN_NEW_TAB = 0;
+ static final int ID_OPEN_IN_INCOGNITO_TAB = 1;
+ static final int ID_REMOVE = 2;
+
+ private static MostVisitedSites sMostVisitedSitesForTests;
+
+ private final Tab mTab;
+ private final TabModelSelector mTabModelSelector;
+ private final Activity mActivity;
+
+ private final Profile mProfile;
+ private final String mTitle;
+ private final int mBackgroundColor;
+ private final NewTabPageView mNewTabPageView;
+
+ private MostVisitedSites mMostVisitedSites;
+ private FaviconHelper mFaviconHelper;
+ private LargeIconBridge mLargeIconBridge;
+ private LogoBridge mLogoBridge;
+ private boolean mSearchProviderHasLogo;
+ private String mOnLogoClickUrl;
+ private FakeboxDelegate mFakeboxDelegate;
+
+ // The timestamp at which the constructor was called.
+ private final long mConstructedTimeNs;
+
+ private boolean mIsLoaded;
+
+ // Whether destroy() has been called.
+ private boolean mIsDestroyed;
+
+ /**
+ * Allows clients to listen for updates to the scroll changes of the search box on the
+ * NTP.
+ */
+ public interface OnSearchBoxScrollListener {
+ /**
+ * Callback to be notified when the scroll position of the search box on the NTP has
+ * changed. A scroll percentage of 0, means the search box has no scroll applied and
+ * is in it's natural resting position. A value of 1 means the search box is scrolled
+ * entirely to the top of the screen viewport.
+ *
+ * @param scrollPercentage The percentage the search box has been scrolled off the page.
+ */
+ void onScrollChanged(float scrollPercentage);
+ }
+
+ /**
+ * Handles user interaction with the fakebox (the URL bar in the NTP).
+ */
+ public interface FakeboxDelegate {
+ /**
+ * Shows the voice recognition dialog. Called when the user taps the microphone icon.
+ */
+ void startVoiceRecognition();
+
+ /**
+ * Focuses the URL bar when the user taps the fakebox, types in the fakebox, or pastes text
+ * into the fakebox.
+ *
+ * @param pastedText The text that was pasted or typed into the fakebox, or null if the user
+ * just tapped the fakebox.
+ */
+ void requestUrlFocusFromFakebox(String pastedText);
+ }
+
+ /**
+ * @param url The URL to check whether it is for the NTP.
+ * @return Whether the passed in URL is used to render the NTP.
+ */
+ public static boolean isNTPUrl(String url) {
+ return url != null && url.startsWith(UrlConstants.NTP_URL);
+ }
+
+ @VisibleForTesting
+ static void setMostVisitedSitesForTests(MostVisitedSites mostVisitedSitesForTests) {
+ sMostVisitedSitesForTests = mostVisitedSitesForTests;
+ }
+
+ private final NewTabPageManager mNewTabPageManager = new NewTabPageManager() {
+ @Override
+ public boolean isLocationBarShownInNTP() {
+ if (mIsDestroyed) return false;
+ Context context = mNewTabPageView.getContext();
+ return isInSingleUrlBarMode(context)
+ && !mNewTabPageView.urlFocusAnimationsDisabled();
+ }
+
+ private void recordOpenedMostVisitedItem(MostVisitedItem item) {
+ if (mIsDestroyed) return;
+ NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_MOST_VISITED_ENTRY);
+ RecordHistogram.recordEnumeratedHistogram("NewTabPage.MostVisited", item.getIndex(),
+ NewTabPageView.MAX_MOST_VISITED_SITES);
+ mMostVisitedSites.recordOpenedMostVisitedItem(item.getIndex());
+ }
+
+ @Override
+ public boolean shouldShowOptOutPromo() {
+ return false;
+ }
+
+ @Override
+ public void optOutPromoShown() {}
+
+ @Override
+ public void optOutPromoClicked(boolean settingsClicked) {
+ assert false : "Should never be called for this page";
+ }
+
+ @Override
+ public void open(MostVisitedItem item) {
+ if (mIsDestroyed) return;
+ recordOpenedMostVisitedItem(item);
+ mTab.loadUrl(new LoadUrlParams(item.getUrl()));
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, OnMenuItemClickListener listener) {
+ if (mIsDestroyed) return;
+ menu.add(Menu.NONE, ID_OPEN_IN_NEW_TAB, Menu.NONE, R.string.contextmenu_open_in_new_tab)
+ .setOnMenuItemClickListener(listener);
+ if (PrefServiceBridge.getInstance().isIncognitoModeEnabled()) {
+ menu.add(Menu.NONE, ID_OPEN_IN_INCOGNITO_TAB, Menu.NONE,
+ R.string.contextmenu_open_in_incognito_tab).setOnMenuItemClickListener(
+ listener);
+ }
+ menu.add(Menu.NONE, ID_REMOVE, Menu.NONE, R.string.remove)
+ .setOnMenuItemClickListener(listener);
+ }
+
+ @Override
+ public boolean onMenuItemClick(int menuId, MostVisitedItem item) {
+ if (mIsDestroyed) return false;
+ switch (menuId) {
+ case ID_OPEN_IN_NEW_TAB:
+ recordOpenedMostVisitedItem(item);
+ mTabModelSelector.openNewTab(new LoadUrlParams(item.getUrl()),
+ TabLaunchType.FROM_LONGPRESS_BACKGROUND, mTab, false);
+ return true;
+ case ID_OPEN_IN_INCOGNITO_TAB:
+ recordOpenedMostVisitedItem(item);
+ mTabModelSelector.openNewTab(new LoadUrlParams(item.getUrl()),
+ TabLaunchType.FROM_LONGPRESS_FOREGROUND, mTab, true);
+ return true;
+ case ID_REMOVE:
+ mMostVisitedSites.blacklistUrl(item.getUrl());
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void navigateToBookmarks() {
+ if (mIsDestroyed) return;
+ RecordUserAction.record("MobileNTPSwitchToBookmarks");
+ if (!EnhancedBookmarkUtils.showEnhancedBookmarkIfEnabled(mActivity)) {
+ mTab.loadUrl(new LoadUrlParams(UrlConstants.BOOKMARKS_URL));
+ }
+ }
+
+ @Override
+ public void navigateToRecentTabs() {
+ if (mIsDestroyed) return;
+ RecordUserAction.record("MobileNTPSwitchToOpenTabs");
+ mTab.loadUrl(new LoadUrlParams(UrlConstants.RECENT_TABS_URL));
+ }
+
+ @Override
+ public void focusSearchBox(boolean beginVoiceSearch, String pastedText) {
+ if (mIsDestroyed) return;
+ if (mFakeboxDelegate != null) {
+ if (beginVoiceSearch) {
+ mFakeboxDelegate.startVoiceRecognition();
+ } else {
+ mFakeboxDelegate.requestUrlFocusFromFakebox(pastedText);
+ }
+ }
+ }
+
+ @Override
+ public void setMostVisitedURLsObserver(MostVisitedURLsObserver observer, int numResults) {
+ if (mIsDestroyed) return;
+ mMostVisitedSites.setMostVisitedURLsObserver(observer, numResults);
+ }
+
+ @Override
+ public void getURLThumbnail(String url, ThumbnailCallback thumbnailCallback) {
+ if (mIsDestroyed) return;
+ mMostVisitedSites.getURLThumbnail(url, thumbnailCallback);
+ }
+
+ @Override
+ public void getLocalFaviconImageForURL(
+ String url, int size, FaviconImageCallback faviconCallback) {
+ if (mIsDestroyed) return;
+ if (mFaviconHelper == null) mFaviconHelper = new FaviconHelper();
+ mFaviconHelper.getLocalFaviconImageForURL(mProfile, url, FaviconHelper.FAVICON
+ | FaviconHelper.TOUCH_ICON | FaviconHelper.TOUCH_PRECOMPOSED_ICON, size,
+ faviconCallback);
+ }
+
+ @Override
+ public void getLargeIconForUrl(String url, int size, LargeIconCallback callback) {
+ if (mIsDestroyed) return;
+ if (mLargeIconBridge == null) mLargeIconBridge = new LargeIconBridge();
+ mLargeIconBridge.getLargeIconForUrl(mProfile, url, size, callback);
+ }
+
+ @Override
+ public void openLogoLink() {
+ if (mIsDestroyed) return;
+ if (mOnLogoClickUrl == null) return;
+ mTab.loadUrl(
+ new LoadUrlParams(mOnLogoClickUrl, PageTransition.LINK));
+ }
+
+ @Override
+ public void getSearchProviderLogo(final LogoObserver logoObserver) {
+ if (mIsDestroyed) return;
+ LogoObserver wrapperCallback = new LogoObserver() {
+ @Override
+ public void onLogoAvailable(Logo logo, boolean fromCache) {
+ if (mIsDestroyed) return;
+ mOnLogoClickUrl = logo != null ? logo.onClickUrl : null;
+ logoObserver.onLogoAvailable(logo, fromCache);
+ }
+ };
+ mLogoBridge.getCurrentLogo(wrapperCallback);
+ }
+
+ @Override
+ public void onLoadingComplete() {
+ long loadTimeMs = (System.nanoTime() - mConstructedTimeNs) / 1000000;
+ RecordHistogram.recordTimesHistogram(
+ "Tab.NewTabOnload", loadTimeMs, TimeUnit.MILLISECONDS);
+ mIsLoaded = true;
+
+ if (mIsDestroyed) return;
+ mMostVisitedSites.onLoadingComplete();
+ }
+ };
+
+ /**
+ * Constructs a NewTabPage.
+ * @param activity The activity used for context to create the new tab page's View.
+ * @param tab The Tab that is showing this new tab page.
+ * @param tabModelSelector The TabModelSelector used to open tabs.
+ */
+ public NewTabPage(Activity activity, Tab tab, TabModelSelector tabModelSelector) {
+ mConstructedTimeNs = System.nanoTime();
+
+ mTab = tab;
+ mActivity = activity;
+ mTabModelSelector = tabModelSelector;
+ mProfile = tab.getProfile();
+
+ mTitle = activity.getResources().getString(R.string.button_new_tab);
+ mBackgroundColor = activity.getResources().getColor(R.color.ntp_bg);
+ TemplateUrlService.getInstance().addObserver(this);
+
+ mMostVisitedSites = buildMostVisitedSites(mProfile);
+ mLogoBridge = new LogoBridge(mProfile);
+ mSearchProviderHasLogo = TemplateUrlService.getInstance().isDefaultSearchEngineGoogle();
+
+ LayoutInflater inflater = LayoutInflater.from(activity);
+ mNewTabPageView = (NewTabPageView) inflater.inflate(R.layout.new_tab_page, null);
+ mNewTabPageView.initialize(mNewTabPageManager, isInSingleUrlBarMode(activity),
+ mSearchProviderHasLogo);
+ }
+
+ private static MostVisitedSites buildMostVisitedSites(Profile profile) {
+ if (sMostVisitedSitesForTests != null) {
+ return sMostVisitedSitesForTests;
+ } else {
+ return new MostVisitedSites(profile);
+ }
+ }
+
+ /** @return The view container for the new tab page. */
+ @VisibleForTesting
+ NewTabPageView getNewTabPageView() {
+ return mNewTabPageView;
+ }
+
+ /**
+ * Updates whether the NewTabPage should animate on URL focus changes.
+ * @param disable Whether to disable the animations.
+ */
+ public void setUrlFocusAnimationsDisabled(boolean disable) {
+ mNewTabPageView.setUrlFocusAnimationsDisabled(disable);
+ }
+
+ private boolean isInSingleUrlBarMode(Context context) {
+ return mSearchProviderHasLogo && !DeviceFormFactor.isTablet(context);
+ }
+
+ private void onSearchEngineUpdated() {
+ // TODO(newt): update this if other search providers provide logos.
+ mSearchProviderHasLogo = TemplateUrlService.getInstance().isDefaultSearchEngineGoogle();
+ mNewTabPageView.setSearchProviderHasLogo(mSearchProviderHasLogo);
+ }
+
+ /**
+ * Specifies the percentage the URL is focused during an animation. 1.0 specifies that the URL
+ * bar has focus and has completed the focus animation. 0 is when the URL bar is does not have
+ * any focus.
+ *
+ * @param percent The percentage of the URL bar focus animation.
+ */
+ public void setUrlFocusChangeAnimationPercent(float percent) {
+ mNewTabPageView.setUrlFocusChangeAnimationPercent(percent);
+ }
+
+ /**
+ * Get the bounds of the search box in relation to the top level NewTabPage view.
+ *
+ * @param originalBounds The bounding region of the search box without external transforms
+ * applied. The delta between this and the transformed bounds determines
+ * the amount of scroll applied to this view.
+ * @param transformedBounds The bounding region of the search box including any transforms
+ * applied by the parent view hierarchy up to the NewTabPage view.
+ * This more accurately reflects the current drawing location of the
+ * search box.
+ */
+ public void getSearchBoxBounds(Rect originalBounds, Rect transformedBounds) {
+ mNewTabPageView.getSearchBoxBounds(originalBounds, transformedBounds);
+ }
+
+ /**
+ * @return Whether the location bar is shown in the NTP.
+ */
+ public boolean isLocationBarShownInNTP() {
+ return mNewTabPageManager.isLocationBarShownInNTP();
+ }
+
+ /**
+ * Sets the listener for search box scroll changes.
+ * @param listener The listener to be notified on changes.
+ */
+ public void setSearchBoxScrollListener(OnSearchBoxScrollListener listener) {
+ mNewTabPageView.setSearchBoxScrollListener(listener);
+ }
+
+ /**
+ * Sets the FakeboxDelegate that this pages interacts with.
+ */
+ public void setFakeboxDelegate(FakeboxDelegate fakeboxDelegate) {
+ mFakeboxDelegate = fakeboxDelegate;
+ }
+
+ /**
+ * @return Whether the NTP has finished loaded.
+ */
+ @VisibleForTesting
+ public boolean isLoadedForTests() {
+ return mIsLoaded;
+ }
+
+ // TemplateUrlServiceObserver overrides
+
+ @Override
+ public void onTemplateURLServiceChanged() {
+ onSearchEngineUpdated();
+ }
+
+ // NativePage overrides
+
+ @Override
+ public void destroy() {
+ assert getView().getParent() == null : "Destroy called before removed from window";
+ if (mFaviconHelper != null) {
+ mFaviconHelper.destroy();
+ mFaviconHelper = null;
+ }
+ if (mLargeIconBridge != null) {
+ mLargeIconBridge.destroy();
+ mLargeIconBridge = null;
+ }
+ if (mMostVisitedSites != null) {
+ mMostVisitedSites.destroy();
+ mMostVisitedSites = null;
+ }
+ if (mLogoBridge != null) {
+ mLogoBridge.destroy();
+ mLogoBridge = null;
+ }
+ TemplateUrlService.getInstance().removeObserver(this);
+ mIsDestroyed = true;
+ }
+
+ @Override
+ public String getUrl() {
+ return UrlConstants.NTP_URL;
+ }
+
+ @Override
+ public String getTitle() {
+ return mTitle;
+ }
+
+ @Override
+ public int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
+ @Override
+ public View getView() {
+ return mNewTabPageView;
+ }
+
+ @Override
+ public String getHost() {
+ return UrlConstants.NTP_HOST;
+ }
+
+ @Override
+ public void updateForUrl(String url) {
+ }
+
+ // InvalidationAwareThumbnailProvider
+
+ @Override
+ public boolean shouldCaptureThumbnail() {
+ return mNewTabPageView.shouldCaptureThumbnail();
+ }
+
+ @Override
+ public void captureThumbnail(Canvas canvas) {
+ mNewTabPageView.captureThumbnail(canvas);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698