| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 #include "chrome/browser/ui/search/instant_controller.h" | 5 #include "chrome/browser/ui/search/instant_controller.h" |
| 6 | 6 |
| 7 #include <iterator> | 7 #include <iterator> |
| 8 | 8 |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/prefs/pref_service.h" | 10 #include "base/prefs/pref_service.h" |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 } | 426 } |
| 427 } else if (full_text.empty()) { | 427 } else if (full_text.empty()) { |
| 428 // The user is typing, and backspaced away all omnibox text. Clear | 428 // The user is typing, and backspaced away all omnibox text. Clear |
| 429 // |last_omnibox_text_| so that we don't attempt to set suggestions. | 429 // |last_omnibox_text_| so that we don't attempt to set suggestions. |
| 430 last_omnibox_text_.clear(); | 430 last_omnibox_text_.clear(); |
| 431 last_user_text_.clear(); | 431 last_user_text_.clear(); |
| 432 last_suggestion_ = InstantSuggestion(); | 432 last_suggestion_ = InstantSuggestion(); |
| 433 if (UseTabForSuggestions()) { | 433 if (UseTabForSuggestions()) { |
| 434 // On a search results page, tell it to clear old results. | 434 // On a search results page, tell it to clear old results. |
| 435 instant_tab_->Update(string16(), 0, 0, true); | 435 instant_tab_->Update(string16(), 0, 0, true); |
| 436 } else if (overlay_ && search_mode_.is_origin_ntp()) { | 436 } else if (search_mode_.is_origin_ntp()) { |
| 437 // On the NTP, tell the overlay to clear old results. Don't hide the | 437 // On the NTP, tell the overlay to clear old results. Don't hide the |
| 438 // overlay so it can show a blank page or logo if it wants. | 438 // overlay so it can show a blank page or logo if it wants. |
| 439 overlay_->Update(string16(), 0, 0, true); | 439 overlay_->Update(string16(), 0, 0, true); |
| 440 } else { | 440 } else { |
| 441 HideOverlay(); | 441 HideOverlay(); |
| 442 } | 442 } |
| 443 } else { | 443 } else { |
| 444 // The user switched to a tab with partial text already in the omnibox. | 444 // The user switched to a tab with partial text already in the omnibox. |
| 445 HideOverlay(); | 445 HideOverlay(); |
| 446 | 446 |
| 447 // The new tab may or may not be a search results page; we don't know | 447 // The new tab may or may not be a search results page; we don't know |
| 448 // since SearchModeChanged() hasn't been called yet. If it later turns | 448 // since SearchModeChanged() hasn't been called yet. If it later turns |
| 449 // out to be, we should store |full_text| now, so that if the user hits | 449 // out to be, we should store |full_text| now, so that if the user hits |
| 450 // Enter, we'll send the correct query to instant_tab_->Submit(). If the | 450 // Enter, we'll send the correct query to instant_tab_->Submit(). If the |
| 451 // partial text is not a query (|last_match_was_search_| is false), we | 451 // partial text is not a query (|last_match_was_search_| is false), we |
| 452 // won't Submit(), so no need to worry about that. | 452 // won't Submit(), so no need to worry about that. |
| 453 last_user_text_ = user_text; | 453 last_user_text_ = user_text; |
| 454 last_suggestion_ = InstantSuggestion(); | 454 last_suggestion_ = InstantSuggestion(); |
| 455 } | 455 } |
| 456 return false; | 456 return false; |
| 457 } else if (full_text.empty()) { | 457 } else if (full_text.empty()) { |
| 458 // The user typed a solitary "?". Same as the backspace case above. | 458 // The user typed a solitary "?". Same as the backspace case above. |
| 459 last_omnibox_text_.clear(); | 459 last_omnibox_text_.clear(); |
| 460 last_user_text_.clear(); | 460 last_user_text_.clear(); |
| 461 last_suggestion_ = InstantSuggestion(); | 461 last_suggestion_ = InstantSuggestion(); |
| 462 if (UseTabForSuggestions()) | 462 if (UseTabForSuggestions()) |
| 463 instant_tab_->Update(string16(), 0, 0, true); | 463 instant_tab_->Update(string16(), 0, 0, true); |
| 464 else if (overlay_ && search_mode_.is_origin_ntp()) | 464 else if (search_mode_.is_origin_ntp()) |
| 465 overlay_->Update(string16(), 0, 0, true); | 465 overlay_->Update(string16(), 0, 0, true); |
| 466 else | 466 else |
| 467 HideOverlay(); | 467 HideOverlay(); |
| 468 return false; | 468 return false; |
| 469 } | 469 } |
| 470 } else if (!omnibox_popup_is_open || full_text.empty()) { | 470 } else if (!omnibox_popup_is_open || full_text.empty()) { |
| 471 // In the non-extended case, hide the overlay as long as the user isn't | 471 // In the non-extended case, hide the overlay as long as the user isn't |
| 472 // actively typing a non-empty query. | 472 // actively typing a non-empty query. |
| 473 HideOverlay(); | 473 HideOverlay(); |
| 474 return false; | 474 return false; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 last_transition_type_ = match.transition; | 510 last_transition_type_ = match.transition; |
| 511 url_for_history_ = match.destination_url; | 511 url_for_history_ = match.destination_url; |
| 512 | 512 |
| 513 // Allow search suggestions. In extended mode, SearchModeChanged() will set | 513 // Allow search suggestions. In extended mode, SearchModeChanged() will set |
| 514 // this, but it's not called in non-extended mode, so fake it. | 514 // this, but it's not called in non-extended mode, so fake it. |
| 515 if (!extended_enabled()) | 515 if (!extended_enabled()) |
| 516 search_mode_.mode = SearchMode::MODE_SEARCH_SUGGESTIONS; | 516 search_mode_.mode = SearchMode::MODE_SEARCH_SUGGESTIONS; |
| 517 | 517 |
| 518 if (UseTabForSuggestions()) { | 518 if (UseTabForSuggestions()) { |
| 519 instant_tab_->Update(user_text, selection_start, selection_end, verbatim); | 519 instant_tab_->Update(user_text, selection_start, selection_end, verbatim); |
| 520 } else if (overlay_) { | 520 } else { |
| 521 allow_overlay_to_show_search_suggestions_ = true; | 521 allow_overlay_to_show_search_suggestions_ = true; |
| 522 | 522 |
| 523 overlay_->Update(extended_enabled() ? user_text : full_text, | 523 overlay_->Update(extended_enabled() ? user_text : full_text, |
| 524 selection_start, selection_end, verbatim); | 524 selection_start, selection_end, verbatim); |
| 525 } | 525 } |
| 526 | 526 |
| 527 content::NotificationService::current()->Notify( | 527 content::NotificationService::current()->Notify( |
| 528 chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, | 528 chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, |
| 529 content::Source<InstantController>(this), | 529 content::Source<InstantController>(this), |
| 530 content::NotificationService::NoDetails()); | 530 content::NotificationService::NoDetails()); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 664 results.push_back(result); | 664 results.push_back(result); |
| 665 } | 665 } |
| 666 } | 666 } |
| 667 } | 667 } |
| 668 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 668 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
| 669 "HandleAutocompleteResults: total_results=%d", | 669 "HandleAutocompleteResults: total_results=%d", |
| 670 static_cast<int>(results.size()))); | 670 static_cast<int>(results.size()))); |
| 671 | 671 |
| 672 if (UseTabForSuggestions()) | 672 if (UseTabForSuggestions()) |
| 673 instant_tab_->SendAutocompleteResults(results); | 673 instant_tab_->SendAutocompleteResults(results); |
| 674 else if (overlay_) | 674 else |
| 675 overlay_->SendAutocompleteResults(results); | 675 overlay_->SendAutocompleteResults(results); |
| 676 | 676 |
| 677 content::NotificationService::current()->Notify( | 677 content::NotificationService::current()->Notify( |
| 678 chrome::NOTIFICATION_INSTANT_SENT_AUTOCOMPLETE_RESULTS, | 678 chrome::NOTIFICATION_INSTANT_SENT_AUTOCOMPLETE_RESULTS, |
| 679 content::Source<InstantController>(this), | 679 content::Source<InstantController>(this), |
| 680 content::NotificationService::NoDetails()); | 680 content::NotificationService::NoDetails()); |
| 681 } | 681 } |
| 682 | 682 |
| 683 void InstantController::OnDefaultSearchProviderChanged() { | 683 void InstantController::OnDefaultSearchProviderChanged() { |
| 684 if (ntp_ && extended_enabled()) { | 684 if (ntp_ && extended_enabled()) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 700 | 700 |
| 701 bool InstantController::OnUpOrDownKeyPressed(int count) { | 701 bool InstantController::OnUpOrDownKeyPressed(int count) { |
| 702 if (!extended_enabled()) | 702 if (!extended_enabled()) |
| 703 return false; | 703 return false; |
| 704 | 704 |
| 705 if (!UseTabForSuggestions() && !overlay_) | 705 if (!UseTabForSuggestions() && !overlay_) |
| 706 return false; | 706 return false; |
| 707 | 707 |
| 708 if (UseTabForSuggestions()) | 708 if (UseTabForSuggestions()) |
| 709 instant_tab_->UpOrDownKeyPressed(count); | 709 instant_tab_->UpOrDownKeyPressed(count); |
| 710 else if (overlay_) | 710 else |
| 711 overlay_->UpOrDownKeyPressed(count); | 711 overlay_->UpOrDownKeyPressed(count); |
| 712 | 712 |
| 713 return true; | 713 return true; |
| 714 } | 714 } |
| 715 | 715 |
| 716 void InstantController::OnCancel(const AutocompleteMatch& match, | 716 void InstantController::OnCancel(const AutocompleteMatch& match, |
| 717 const string16& user_text, | 717 const string16& user_text, |
| 718 const string16& full_text) { | 718 const string16& full_text) { |
| 719 if (!extended_enabled()) | 719 if (!extended_enabled()) |
| 720 return; | 720 return; |
| 721 | 721 |
| 722 if (!UseTabForSuggestions() && !overlay_) | 722 if (!UseTabForSuggestions() && !overlay_) |
| 723 return; | 723 return; |
| 724 | 724 |
| 725 // We manually reset the state here since the JS is not expected to do it. | 725 // We manually reset the state here since the JS is not expected to do it. |
| 726 // TODO(sreeram): Handle the case where user_text is now a URL | 726 // TODO(sreeram): Handle the case where user_text is now a URL |
| 727 last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) && | 727 last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) && |
| 728 !full_text.empty(); | 728 !full_text.empty(); |
| 729 last_omnibox_text_ = full_text; | 729 last_omnibox_text_ = full_text; |
| 730 last_user_text_ = user_text; | 730 last_user_text_ = user_text; |
| 731 last_suggestion_ = InstantSuggestion(); | 731 last_suggestion_ = InstantSuggestion(); |
| 732 | 732 |
| 733 // Say |full_text| is "amazon.com" and |user_text| is "ama". This means the | 733 // Say |full_text| is "amazon.com" and |user_text| is "ama". This means the |
| 734 // inline autocompletion is "zon.com"; so the selection should span from | 734 // inline autocompletion is "zon.com"; so the selection should span from |
| 735 // user_text.size() to full_text.size(). The selection bounds are inverted | 735 // user_text.size() to full_text.size(). The selection bounds are inverted |
| 736 // because the caret is at the end of |user_text|, not |full_text|. | 736 // because the caret is at the end of |user_text|, not |full_text|. |
| 737 if (UseTabForSuggestions()) { | 737 if (UseTabForSuggestions()) { |
| 738 instant_tab_->CancelSelection(user_text, full_text.size(), user_text.size(), | 738 instant_tab_->CancelSelection(user_text, full_text.size(), user_text.size(), |
| 739 last_verbatim_); | 739 last_verbatim_); |
| 740 } else if (overlay_) { | 740 } else { |
| 741 overlay_->CancelSelection(user_text, full_text.size(), user_text.size(), | 741 overlay_->CancelSelection(user_text, full_text.size(), user_text.size(), |
| 742 last_verbatim_); | 742 last_verbatim_); |
| 743 } | 743 } |
| 744 } | 744 } |
| 745 | 745 |
| 746 void InstantController::OmniboxNavigateToURL() { | 746 void InstantController::OmniboxNavigateToURL() { |
| 747 RecordNavigationHistogram(UsingLocalPage(), false, extended_enabled()); | 747 RecordNavigationHistogram(UsingLocalPage(), false, extended_enabled()); |
| 748 if (!extended_enabled()) | 748 if (!extended_enabled()) |
| 749 return; | 749 return; |
| 750 if (UseTabForSuggestions()) | 750 if (UseTabForSuggestions()) |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 last_suggestion_.behavior == INSTANT_COMPLETE_NEVER)) { | 843 last_suggestion_.behavior == INSTANT_COMPLETE_NEVER)) { |
| 844 last_suggestion_.text.clear(); | 844 last_suggestion_.text.clear(); |
| 845 instant_tab_->Submit(last_omnibox_text_); | 845 instant_tab_->Submit(last_omnibox_text_); |
| 846 instant_tab_->contents()->GetView()->Focus(); | 846 instant_tab_->contents()->GetView()->Focus(); |
| 847 EnsureSearchTermsAreSet(instant_tab_->contents(), last_omnibox_text_); | 847 EnsureSearchTermsAreSet(instant_tab_->contents(), last_omnibox_text_); |
| 848 return true; | 848 return true; |
| 849 } | 849 } |
| 850 return false; | 850 return false; |
| 851 } | 851 } |
| 852 | 852 |
| 853 if (!overlay_) | |
| 854 return false; | |
| 855 | |
| 856 // If the overlay is not showing at all, don't commit it. | 853 // If the overlay is not showing at all, don't commit it. |
| 857 if (!model_.mode().is_search_suggestions()) | 854 if (!model_.mode().is_search_suggestions()) |
| 858 return false; | 855 return false; |
| 859 | 856 |
| 860 // If the overlay is showing at full height (with results), commit it. | 857 // If the overlay is showing at full height (with results), commit it. |
| 861 // If it's showing at parial height, commit if it's navigating. | 858 // If it's showing at parial height, commit if it's navigating. |
| 862 if (!IsOverlayingSearchResults() && type != INSTANT_COMMIT_NAVIGATED) | 859 if (!IsOverlayingSearchResults() && type != INSTANT_COMMIT_NAVIGATED) |
| 863 return false; | 860 return false; |
| 864 | 861 |
| 865 // There may re-entrance here, from the call to browser_->CommitInstant below, | 862 // There may re-entrance here, from the call to browser_->CommitInstant below, |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 return; | 1116 return; |
| 1120 | 1117 |
| 1121 // If the overlay is showing or the omnibox has focus, don't refresh the | 1118 // If the overlay is showing or the omnibox has focus, don't refresh the |
| 1122 // overlay. It will get refreshed the next time the overlay is hidden or the | 1119 // overlay. It will get refreshed the next time the overlay is hidden or the |
| 1123 // omnibox loses focus. | 1120 // omnibox loses focus. |
| 1124 if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE && model_.mode().is_default()) | 1121 if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE && model_.mode().is_default()) |
| 1125 ResetOverlay(GetInstantURL()); | 1122 ResetOverlay(GetInstantURL()); |
| 1126 } | 1123 } |
| 1127 | 1124 |
| 1128 void InstantController::OverlayLoadCompletedMainFrame() { | 1125 void InstantController::OverlayLoadCompletedMainFrame() { |
| 1129 if (!overlay_ || overlay_->supports_instant()) | 1126 if (overlay_->supports_instant()) |
| 1130 return; | 1127 return; |
| 1131 InstantService* instant_service = | 1128 InstantService* instant_service = |
| 1132 InstantServiceFactory::GetForProfile(browser_->profile()); | 1129 InstantServiceFactory::GetForProfile(browser_->profile()); |
| 1133 content::WebContents* contents = overlay_->contents(); | 1130 content::WebContents* contents = overlay_->contents(); |
| 1134 DCHECK(contents); | 1131 DCHECK(contents); |
| 1135 if (instant_service->IsInstantProcess( | 1132 if (instant_service->IsInstantProcess( |
| 1136 contents->GetRenderProcessHost()->GetID())) { | 1133 contents->GetRenderProcessHost()->GetID())) { |
| 1137 return; | 1134 return; |
| 1138 } | 1135 } |
| 1139 InstantSupportDetermined(contents, false); | 1136 InstantSupportDetermined(contents, false); |
| (...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1628 return false; | 1625 return false; |
| 1629 | 1626 |
| 1630 // The preloaded NTP does not support instant yet. If we're not in startup, | 1627 // The preloaded NTP does not support instant yet. If we're not in startup, |
| 1631 // always fall back to the local NTP. If we are in startup, use the local NTP | 1628 // always fall back to the local NTP. If we are in startup, use the local NTP |
| 1632 // (unless the finch flag to use the remote NTP is set). | 1629 // (unless the finch flag to use the remote NTP is set). |
| 1633 return !(InStartup() && chrome::ShouldPreferRemoteNTPOnStartup()); | 1630 return !(InStartup() && chrome::ShouldPreferRemoteNTPOnStartup()); |
| 1634 } | 1631 } |
| 1635 | 1632 |
| 1636 void InstantController::ResetOverlay(const std::string& instant_url) { | 1633 void InstantController::ResetOverlay(const std::string& instant_url) { |
| 1637 HideInternal(); | 1634 HideInternal(); |
| 1638 overlay_.reset(); | 1635 // If there's no active tab, the browser is opening or closing. |
| 1636 const content::WebContents* active_tab = browser_->GetActiveWebContents(); |
| 1637 if (!active_tab || instant_url.empty()) { |
| 1638 overlay_.reset(); |
| 1639 } else { |
| 1640 overlay_.reset(new InstantOverlay(this, instant_url)); |
| 1641 overlay_->InitContents(browser_->profile(), active_tab); |
| 1642 } |
| 1643 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
| 1644 "ResetOverlay: instant_url='%s'", instant_url.c_str())); |
| 1639 } | 1645 } |
| 1640 | 1646 |
| 1641 InstantController::InstantFallbackReason | 1647 InstantController::InstantFallbackReason |
| 1642 InstantController::ShouldSwitchToLocalOverlay() const { | 1648 InstantController::ShouldSwitchToLocalOverlay() const { |
| 1643 if (!extended_enabled()) | 1649 if (!extended_enabled()) |
| 1644 return INSTANT_FALLBACK_NONE; | 1650 return INSTANT_FALLBACK_NONE; |
| 1645 | 1651 |
| 1646 if (!overlay()) | 1652 if (!overlay()) |
| 1647 return DetermineFallbackReason(NULL, std::string()); | 1653 return DetermineFallbackReason(NULL, std::string()); |
| 1648 | 1654 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1720 | 1726 |
| 1721 // Clear the first interaction timestamp for later use. | 1727 // Clear the first interaction timestamp for later use. |
| 1722 first_interaction_time_ = base::Time(); | 1728 first_interaction_time_ = base::Time(); |
| 1723 first_interaction_time_recorded_ = false; | 1729 first_interaction_time_recorded_ = false; |
| 1724 | 1730 |
| 1725 if (instant_tab_) | 1731 if (instant_tab_) |
| 1726 use_tab_for_suggestions_ = true; | 1732 use_tab_for_suggestions_ = true; |
| 1727 } | 1733 } |
| 1728 | 1734 |
| 1729 void InstantController::ShowOverlay(int height, InstantSizeUnits units) { | 1735 void InstantController::ShowOverlay(int height, InstantSizeUnits units) { |
| 1730 // Nothing to see here. | |
| 1731 if (!overlay_) | |
| 1732 return; | |
| 1733 | |
| 1734 // If we are on a committed search results page, the |overlay_| is not in use. | 1736 // If we are on a committed search results page, the |overlay_| is not in use. |
| 1735 if (UseTabForSuggestions()) | 1737 if (UseTabForSuggestions()) |
| 1736 return; | 1738 return; |
| 1737 | 1739 |
| 1738 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 1740 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
| 1739 "Show: height=%d units=%d", height, units)); | 1741 "Show: height=%d units=%d", height, units)); |
| 1740 | 1742 |
| 1741 // Must have updated omnibox after the last HideOverlay() to show suggestions. | 1743 // Must have updated omnibox after the last HideOverlay() to show suggestions. |
| 1742 if (!allow_overlay_to_show_search_suggestions_) | 1744 if (!allow_overlay_to_show_search_suggestions_) |
| 1743 return; | 1745 return; |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1914 bool js_webkit_enabled = profile()->GetPrefs()->GetBoolean( | 1916 bool js_webkit_enabled = profile()->GetPrefs()->GetBoolean( |
| 1915 prefs::kWebKitJavascriptEnabled); | 1917 prefs::kWebKitJavascriptEnabled); |
| 1916 return js_content_enabled && js_webkit_enabled; | 1918 return js_content_enabled && js_webkit_enabled; |
| 1917 } | 1919 } |
| 1918 | 1920 |
| 1919 bool InstantController::InStartup() const { | 1921 bool InstantController::InStartup() const { |
| 1920 // TODO(shishir): This is not completely reliable. Find a better way to detect | 1922 // TODO(shishir): This is not completely reliable. Find a better way to detect |
| 1921 // startup time. | 1923 // startup time. |
| 1922 return !browser_->GetActiveWebContents(); | 1924 return !browser_->GetActiveWebContents(); |
| 1923 } | 1925 } |
| OLD | NEW |