#include "base/metrics/histogram.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
-#include "build/build_config.h"
-#include "chrome/browser/history/most_visited_tiles_experiment.h"
-#include "chrome/browser/history/top_sites.h"
+#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/instant_service.h"
#include "chrome/browser/search/instant_service_factory.h"
#include "chrome/browser/search/search.h"
-#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/app_list/app_list_util.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
+#include "chrome/browser/ui/search/instant_search_prerenderer.h"
#include "chrome/browser/ui/search/search_ipc_router_policy_impl.h"
+#include "chrome/browser/ui/search/search_tab_helper_delegate.h"
#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_utils.h"
#include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
#include "chrome/common/url_constants.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/google/core/browser/google_util.h"
+#include "components/search/search.h"
+#include "components/signin/core/browser/signin_manager.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_type.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/page_transition_types.h"
#include "content/public/common/referrer.h"
-#include "grit/generated_resources.h"
#include "net/base/net_errors.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(SearchTabHelper);
contents->GetRenderProcessHost()->GetID());
}
-// Updates the location bar to reflect |contents| Instant support state.
-void UpdateLocationBar(content::WebContents* contents) {
-// iOS and Android don't use the Instant framework.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
- if (!contents)
- return;
-
- Browser* browser = chrome::FindBrowserWithWebContents(contents);
- if (!browser)
- return;
- browser->OnWebContentsInstantSupportDisabled(contents);
-#endif
-}
-
// Called when an NTP finishes loading. If the load start time was noted,
// calculates and logs the total load time.
void RecordNewTabLoadTime(content::WebContents* contents) {
base::TimeDelta duration =
base::TimeTicks::Now() - core_tab_helper->new_tab_start_time();
- UMA_HISTOGRAM_TIMES("Tab.NewTabOnload", duration);
+ if (IsCacheableNTP(contents)) {
+ if (google_util::IsGoogleDomainUrl(
+ contents->GetController().GetLastCommittedEntry()->GetURL(),
+ google_util::ALLOW_SUBDOMAIN,
+ google_util::DISALLOW_NON_STANDARD_PORTS)) {
+ UMA_HISTOGRAM_TIMES("Tab.NewTabOnload.Google", duration);
+ } else {
+ UMA_HISTOGRAM_TIMES("Tab.NewTabOnload.Other", duration);
+ }
+ } else {
+ UMA_HISTOGRAM_TIMES("Tab.NewTabOnload.Local", duration);
+ }
core_tab_helper->set_new_tab_start_time(base::TimeTicks());
}
+// Returns true if the user is signed in and full history sync is enabled,
+// and false otherwise.
+bool IsHistorySyncEnabled(Profile* profile) {
+ ProfileSyncService* sync =
+ ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
+ return sync &&
+ sync->SyncActive() &&
+ sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES);
+}
+
+bool OmniboxHasFocus(OmniboxView* omnibox) {
+ return omnibox && omnibox->model()->has_focus();
+}
+
} // namespace
SearchTabHelper::SearchTabHelper(content::WebContents* web_contents)
: WebContentsObserver(web_contents),
is_search_enabled_(chrome::IsInstantExtendedAPIEnabled()),
- user_input_in_progress_(false),
web_contents_(web_contents),
- ipc_router_(web_contents, this,
- make_scoped_ptr(new SearchIPCRouterPolicyImpl(web_contents))
- .PassAs<SearchIPCRouter::Policy>()),
- instant_service_(NULL) {
+ ipc_router_(web_contents,
+ this,
+ make_scoped_ptr(new SearchIPCRouterPolicyImpl(web_contents))),
+ instant_service_(NULL),
+ delegate_(NULL),
+ omnibox_has_focus_fn_(&OmniboxHasFocus) {
if (!is_search_enabled_)
return;
UpdateMode(true, true);
}
-void SearchTabHelper::OmniboxEditModelChanged(bool user_input_in_progress,
- bool cancelling) {
+void SearchTabHelper::OmniboxInputStateChanged() {
if (!is_search_enabled_)
return;
- user_input_in_progress_ = user_input_in_progress;
- if (!user_input_in_progress && !cancelling)
- return;
-
UpdateMode(false, false);
}
+void SearchTabHelper::OmniboxFocusChanged(OmniboxFocusState state,
+ OmniboxFocusChangeReason reason) {
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_OMNIBOX_FOCUS_CHANGED,
+ content::Source<SearchTabHelper>(this),
+ content::NotificationService::NoDetails());
+
+ ipc_router_.OmniboxFocusChanged(state, reason);
+
+ // Don't send oninputstart/oninputend updates in response to focus changes
+ // if there's a navigation in progress. This prevents Chrome from sending
+ // a spurious oninputend when the user accepts a match in the omnibox.
+ if (web_contents_->GetController().GetPendingEntry() == NULL) {
+ ipc_router_.SetInputInProgress(IsInputInProgress());
+
+ InstantSearchPrerenderer* prerenderer =
+ InstantSearchPrerenderer::GetForProfile(profile());
+ if (!prerenderer || !chrome::ShouldPrerenderInstantUrlOnOmniboxFocus())
+ return;
+
+ if (state == OMNIBOX_FOCUS_NONE) {
+ prerenderer->Cancel();
+ return;
+ }
+
+ if (!IsSearchResultsPage()) {
+ prerenderer->Init(
+ web_contents_->GetController().GetSessionStorageNamespaceMap(),
+ web_contents_->GetContainerBounds().size());
+ }
+ }
+}
+
void SearchTabHelper::NavigationEntryUpdated() {
if (!is_search_enabled_)
return;
model_.SetInstantSupportState(new_state);
content::NavigationEntry* entry =
- web_contents_->GetController().GetVisibleEntry();
+ web_contents_->GetController().GetLastCommittedEntry();
if (entry) {
chrome::SetInstantSupportStateInNavigationEntry(new_state, entry);
- if (!instant_support)
- UpdateLocationBar(web_contents_);
+ if (delegate_ && !instant_support)
+ delegate_->OnWebContentsInstantSupportDisabled(web_contents_);
}
}
ipc_router_.SetSuggestionToPrefetch(suggestion);
}
-void SearchTabHelper::Submit(const base::string16& text) {
- ipc_router_.Submit(text);
+void SearchTabHelper::Submit(const base::string16& text,
+ const EmbeddedSearchRequestParams& params) {
+ ipc_router_.Submit(text, params);
}
void SearchTabHelper::OnTabActivated() {
ipc_router_.OnTabActivated();
+
+ OmniboxView* omnibox_view = GetOmniboxView();
+ if (chrome::ShouldPrerenderInstantUrlOnOmniboxFocus() &&
+ omnibox_has_focus_fn_(omnibox_view)) {
+ InstantSearchPrerenderer* prerenderer =
+ InstantSearchPrerenderer::GetForProfile(profile());
+ if (prerenderer && !IsSearchResultsPage()) {
+ prerenderer->Init(
+ web_contents_->GetController().GetSessionStorageNamespaceMap(),
+ web_contents_->GetContainerBounds().size());
+ }
+ }
}
void SearchTabHelper::OnTabDeactivated() {
}
void SearchTabHelper::DidFailProvisionalLoad(
- int64 /* frame_id */,
- const base::string16& /* frame_unique_name */,
- bool is_main_frame,
+ content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
- const base::string16& /* error_description */,
- content::RenderViewHost* /* render_view_host */) {
+ const base::string16& /* error_description */) {
// If error_code is ERR_ABORTED means that the user has canceled this
// navigation so it shouldn't be redirected.
- if (is_main_frame &&
- error_code != net::ERR_ABORTED &&
+ if (!render_frame_host->GetParent() && error_code != net::ERR_ABORTED &&
validated_url != GURL(chrome::kChromeSearchLocalNtpUrl) &&
chrome::IsNTPURL(validated_url, profile())) {
RedirectToLocalNTP();
}
}
-void SearchTabHelper::DidFinishLoad(
- int64 /* frame_id */,
- const GURL& /* validated_url */,
- bool is_main_frame,
- content::RenderViewHost* /* render_view_host */) {
- if (is_main_frame) {
+void SearchTabHelper::DidFinishLoad(content::RenderFrameHost* render_frame_host,
+ const GURL& /* validated_url */) {
+ if (!render_frame_host->GetParent()) {
if (chrome::IsInstantNTP(web_contents_))
RecordNewTabLoadTime(web_contents_);
// location bar from here to turn off search terms replacement.
chrome::SetInstantSupportStateInNavigationEntry(model_.instant_support(),
entry);
- if (model_.instant_support() == INSTANT_SUPPORT_NO)
- UpdateLocationBar(web_contents_);
+ if (delegate_ && model_.instant_support() == INSTANT_SUPPORT_NO)
+ delegate_->OnWebContentsInstantSupportDisabled(web_contents_);
return;
}
model_.SetVoiceSearchSupported(false);
chrome::SetInstantSupportStateInNavigationEntry(model_.instant_support(),
entry);
+
+ if (InInstantProcess(profile(), web_contents_))
+ ipc_router_.OnNavigationEntryCommitted();
}
void SearchTabHelper::OnInstantSupportDetermined(bool supports_instant) {
void SearchTabHelper::MostVisitedItemsChanged(
const std::vector<InstantMostVisitedItem>& items) {
- std::vector<InstantMostVisitedItem> items_copy(items);
- MaybeRemoveMostVisitedItems(&items_copy);
- ipc_router_.SendMostVisitedItems(items_copy);
+ ipc_router_.SendMostVisitedItems(items);
}
void SearchTabHelper::OmniboxStartMarginChanged(int omnibox_start_margin) {
ipc_router_.SetOmniboxStartMargin(omnibox_start_margin);
}
-void SearchTabHelper::MaybeRemoveMostVisitedItems(
- std::vector<InstantMostVisitedItem>* items) {
-// The code below uses APIs not available on Android and the experiment should
-// not run there.
-#if !defined(OS_ANDROID)
- if (!history::MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled())
- return;
-
- Profile* profile =
- Profile::FromBrowserContext(web_contents_->GetBrowserContext());
- if (!profile)
- return;
-
- Browser* browser = chrome::FindBrowserWithProfile(profile,
- chrome::GetActiveDesktop());
- if (!browser)
- return;
-
- TabStripModel* tab_strip_model = browser->tab_strip_model();
- history::TopSites* top_sites = profile->GetTopSites();
- if (!tab_strip_model || !top_sites) {
- NOTREACHED();
- return;
- }
-
- std::set<std::string> open_urls;
- chrome::GetOpenUrls(*tab_strip_model, *top_sites, &open_urls);
- history::MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(
- open_urls, items);
-#endif
-}
-
void SearchTabHelper::FocusOmnibox(OmniboxFocusState state) {
-// iOS and Android don't use the Instant framework.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
- Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
- if (!browser)
+// TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
+#if !defined(OS_ANDROID)
+ OmniboxView* omnibox = GetOmniboxView();
+ if (!omnibox)
return;
- OmniboxView* omnibox = browser->window()->GetLocationBar()->GetOmniboxView();
// Do not add a default case in the switch block for the following reasons:
// (1) Explicitly handle the new states. If new states are added in the
// OmniboxFocusState, the compiler will warn the developer to handle the new
// from changing the omnibox value and closing the popup without user
// interaction.
if (!omnibox->model()->popup_model()->IsOpen())
- web_contents()->GetView()->Focus();
+ web_contents()->Focus();
break;
}
#endif
void SearchTabHelper::NavigateToURL(const GURL& url,
WindowOpenDisposition disposition,
bool is_most_visited_item_url) {
-// iOS and Android don't use the Instant framework.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
- // TODO(kmadhusu): Remove chrome::FindBrowser...() function call from here.
- // Create a SearchTabHelperDelegate interface and have the Browser object
- // implement that interface to provide the necessary functionality.
- Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
- Profile* profile =
- Profile::FromBrowserContext(web_contents_->GetBrowserContext());
- if (!browser || !profile)
- return;
-
if (is_most_visited_item_url) {
content::RecordAction(
base::UserMetricsAction("InstantExtended.MostVisitedClicked"));
}
- chrome::NavigateParams params(browser, url,
- content::PAGE_TRANSITION_AUTO_BOOKMARK);
- params.referrer = content::Referrer();
- params.source_contents = web_contents_;
- params.disposition = disposition;
- params.is_renderer_initiated = false;
- params.initiating_profile = profile;
- chrome::Navigate(¶ms);
-#endif
+ if (delegate_)
+ delegate_->NavigateOnThumbnailClick(url, disposition, web_contents_);
}
void SearchTabHelper::OnDeleteMostVisitedItem(const GURL& url) {
}
void SearchTabHelper::OnLogEvent(NTPLoggingEventType event) {
+// TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
+#if !defined(OS_ANDROID)
NTPUserDataLogger::GetOrCreateFromWebContents(
web_contents())->LogEvent(event);
+#endif
}
-void SearchTabHelper::OnLogImpression(int position,
- const base::string16& provider) {
+void SearchTabHelper::OnLogMostVisitedImpression(
+ int position, const base::string16& provider) {
+// TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
+#if !defined(OS_ANDROID)
NTPUserDataLogger::GetOrCreateFromWebContents(
- web_contents())->LogImpression(position, provider);
+ web_contents())->LogMostVisitedImpression(position, provider);
+#endif
+}
+
+void SearchTabHelper::OnLogMostVisitedNavigation(
+ int position, const base::string16& provider) {
+// TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
+#if !defined(OS_ANDROID)
+ NTPUserDataLogger::GetOrCreateFromWebContents(
+ web_contents())->LogMostVisitedNavigation(position, provider);
+#endif
}
void SearchTabHelper::PasteIntoOmnibox(const base::string16& text) {
-// iOS and Android don't use the Instant framework.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
- Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
- if (!browser)
+// TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
+#if !defined(OS_ANDROID)
+ OmniboxView* omnibox = GetOmniboxView();
+ if (!omnibox)
return;
-
- OmniboxView* omnibox = browser->window()->GetLocationBar()->GetOmniboxView();
// The first case is for right click to paste, where the text is retrieved
// from the clipboard already sanitized. The second case is needed to handle
// drag-and-drop value and it has to be sanitazed before setting it into the
if (manager) {
const base::string16 username =
base::UTF8ToUTF16(manager->GetAuthenticatedUsername());
- ipc_router_.SendChromeIdentityCheckResult(identity,
- identity == username);
+ // The identity check only passes if the user is syncing their history.
+ // TODO(beaudoin): Change this function name and related APIs now that it's
+ // checking both the identity and the user's sync state.
+ bool matches = IsHistorySyncEnabled(profile()) && identity == username;
+ ipc_router_.SendChromeIdentityCheckResult(identity, matches);
}
}
}
if (!update_origin)
origin = model_.mode().origin;
- if (user_input_in_progress_)
+
+ OmniboxView* omnibox = GetOmniboxView();
+ if (omnibox && omnibox->model()->user_input_in_progress())
type = SearchMode::MODE_SEARCH_SUGGESTIONS;
+
+ SearchMode old_mode(model_.mode());
model_.SetMode(SearchMode(type, origin));
+ if (old_mode.is_ntp() != model_.mode().is_ntp()) {
+ ipc_router_.SetInputInProgress(IsInputInProgress());
+ }
}
void SearchTabHelper::DetermineIfPageSupportsInstant() {
content::NavigationController::LoadURLParams load_params(
(GURL(chrome::kChromeSearchLocalNtpUrl)));
load_params.referrer = content::Referrer();
- load_params.transition_type = content::PAGE_TRANSITION_SERVER_REDIRECT;
+ load_params.transition_type = ui::PAGE_TRANSITION_SERVER_REDIRECT;
// Don't push a history entry.
load_params.should_replace_current_entry = true;
web_contents_->GetController().LoadURLWithParams(load_params);
}
+
+bool SearchTabHelper::IsInputInProgress() const {
+ OmniboxView* omnibox = GetOmniboxView();
+ return !model_.mode().is_ntp() && omnibox &&
+ omnibox->model()->focus_state() == OMNIBOX_FOCUS_VISIBLE;
+}
+
+OmniboxView* SearchTabHelper::GetOmniboxView() const {
+ return delegate_ ? delegate_->GetOmniboxView() : NULL;
+}