blob: 02ab9e9899d24bf5459066e0815075e91b0ab080 [file] [log] [blame]
[email protected]f4f50ef2011-01-21 19:01:191// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]c8865482009-07-23 20:40:102// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/omnibox_search_hint.h"
6
[email protected]c8865482009-07-23 20:40:107#include "base/command_line.h"
[email protected]835d7c82010-10-14 04:38:388#include "base/metrics/histogram.h"
[email protected]c8865482009-07-23 20:40:109#include "base/task.h"
[email protected]d1318572010-12-29 22:37:4510// TODO(avi): remove when conversions not needed any more
11#include "base/utf_string_conversions.h"
[email protected]9ac40092010-10-27 23:05:2612#include "chrome/browser/autocomplete/autocomplete.h"
[email protected]12802702010-07-09 19:43:0913#include "chrome/browser/autocomplete/autocomplete_edit.h"
[email protected]9ac40092010-10-27 23:05:2614#include "chrome/browser/autocomplete/autocomplete_match.h"
[email protected]7e204122011-09-01 18:56:2115#include "chrome/browser/infobars/infobar_tab_helper.h"
[email protected]37858e52010-08-26 00:22:0216#include "chrome/browser/prefs/pref_service.h"
[email protected]8ecad5e2010-12-02 21:18:3317#include "chrome/browser/profiles/profile.h"
[email protected]8b62334b2010-08-31 22:37:1118#include "chrome/browser/search_engines/template_url.h"
[email protected]8e5c89a2011-06-07 18:13:3319#include "chrome/browser/search_engines/template_url_service.h"
20#include "chrome/browser/search_engines/template_url_service_factory.h"
[email protected]7cceebac2011-03-03 00:32:2121#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
[email protected]71b73f02011-04-06 15:57:2922#include "chrome/browser/ui/browser_list.h"
[email protected]00070c732011-04-09 15:31:3323#include "chrome/browser/ui/browser_window.h"
[email protected]6a3ec2312010-12-02 19:30:1924#include "chrome/browser/ui/omnibox/location_bar.h"
[email protected]b76ac712011-05-03 22:17:1125#include "chrome/browser/ui/omnibox/omnibox_view.h"
[email protected]7abc95292011-05-18 00:18:0926#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
[email protected]432115822011-07-10 15:52:2727#include "chrome/common/chrome_notification_types.h"
[email protected]c8865482009-07-23 20:40:1028#include "chrome/common/chrome_switches.h"
[email protected]c8865482009-07-23 20:40:1029#include "chrome/common/pref_names.h"
[email protected]8286f51a2011-05-31 17:39:1330#include "content/browser/tab_contents/navigation_details.h"
[email protected]b3841c502011-03-09 01:21:3131#include "content/common/notification_details.h"
32#include "content/common/notification_source.h"
[email protected]0d6e9bd2011-10-18 04:29:1633#include "content/public/browser/notification_types.h"
[email protected]c8865482009-07-23 20:40:1034#include "grit/generated_resources.h"
[email protected]6e4baff2011-04-29 18:07:5535#include "grit/theme_resources_standard.h"
[email protected]c051a1b2011-01-21 23:30:1736#include "ui/base/l10n/l10n_util.h"
[email protected]42ce29d2011-01-20 23:19:4637#include "ui/base/resource/resource_bundle.h"
[email protected]c8865482009-07-23 20:40:1038
39// The URLs of search engines for which we want to trigger the infobar.
[email protected]cfd03402011-09-23 19:27:1840const char* const kSearchEngineURLs[] = {
[email protected]c8865482009-07-23 20:40:1041 "http://www.google.com/",
42 "http://www.yahoo.com/",
43 "http://www.bing.com/",
44 "http://www.altavista.com/",
45 "http://www.ask.com/",
46 "http://www.wolframalpha.com/",
47};
48
[email protected]f4f50ef2011-01-21 19:01:1949
50// HintInfoBar ----------------------------------------------------------------
51
[email protected]c8865482009-07-23 20:40:1052class HintInfoBar : public ConfirmInfoBarDelegate {
53 public:
[email protected]f4f50ef2011-01-21 19:01:1954 explicit HintInfoBar(OmniboxSearchHint* omnibox_hint);
[email protected]c8865482009-07-23 20:40:1055
56 private:
[email protected]f4f50ef2011-01-21 19:01:1957 virtual ~HintInfoBar();
58
59 void AllowExpiry() { should_expire_ = true; }
60
61 // ConfirmInfoBarDelegate:
62 virtual bool ShouldExpire(
[email protected]8286f51a2011-05-31 17:39:1363 const content::LoadCommittedDetails& details) const OVERRIDE;
[email protected]e3c31d272011-05-05 02:12:1064 virtual void InfoBarDismissed() OVERRIDE;
65 virtual gfx::Image* GetIcon() const OVERRIDE;
66 virtual Type GetInfoBarType() const OVERRIDE;
67 virtual string16 GetMessageText() const OVERRIDE;
68 virtual int GetButtons() const OVERRIDE;
69 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
70 virtual bool Accept() OVERRIDE;
[email protected]f4f50ef2011-01-21 19:01:1971
[email protected]c8865482009-07-23 20:40:1072 // The omnibox hint that shows us.
73 OmniboxSearchHint* omnibox_hint_;
74
75 // Whether the user clicked one of the buttons.
76 bool action_taken_;
77
78 // Whether the info-bar should be dismissed on the next navigation.
79 bool should_expire_;
80
81 // Used to delay the expiration of the info-bar.
82 ScopedRunnableMethodFactory<HintInfoBar> method_factory_;
83
84 DISALLOW_COPY_AND_ASSIGN(HintInfoBar);
85};
86
[email protected]f4f50ef2011-01-21 19:01:1987HintInfoBar::HintInfoBar(OmniboxSearchHint* omnibox_hint)
[email protected]95a33ed62011-09-30 15:07:0888 : ConfirmInfoBarDelegate(omnibox_hint->tab()->infobar_tab_helper()),
[email protected]f4f50ef2011-01-21 19:01:1989 omnibox_hint_(omnibox_hint),
90 action_taken_(false),
91 should_expire_(false),
92 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
93 // We want the info-bar to stick-around for few seconds and then be hidden
94 // on the next navigation after that.
95 MessageLoop::current()->PostDelayedTask(FROM_HERE,
96 method_factory_.NewRunnableMethod(&HintInfoBar::AllowExpiry),
97 8000); // 8 seconds.
98}
[email protected]ec8f51162011-02-08 04:20:4099
[email protected]f4f50ef2011-01-21 19:01:19100HintInfoBar::~HintInfoBar() {
[email protected]e3c31d272011-05-05 02:12:10101 if (!action_taken_)
102 UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Ignored", 1);
[email protected]f4f50ef2011-01-21 19:01:19103}
104
105bool HintInfoBar::ShouldExpire(
[email protected]8286f51a2011-05-31 17:39:13106 const content::LoadCommittedDetails& details) const {
[email protected]4e697b042011-07-08 06:44:56107 return details.is_navigation_to_different_page() && should_expire_;
[email protected]f4f50ef2011-01-21 19:01:19108}
109
110void HintInfoBar::InfoBarDismissed() {
111 action_taken_ = true;
112 UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Closed", 1);
113 // User closed the infobar, let's not bug him again with this in the future.
114 omnibox_hint_->DisableHint();
115}
116
[email protected]cf4d5a22011-04-21 22:46:22117gfx::Image* HintInfoBar::GetIcon() const {
118 return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
[email protected]f4f50ef2011-01-21 19:01:19119 IDR_INFOBAR_QUESTION_MARK);
120}
121
122InfoBarDelegate::Type HintInfoBar::GetInfoBarType() const {
123 return PAGE_ACTION_TYPE;
124}
125
126string16 HintInfoBar::GetMessageText() const {
127 return l10n_util::GetStringUTF16(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_TEXT);
128}
129
130int HintInfoBar::GetButtons() const {
131 return BUTTON_OK;
132}
133
134string16 HintInfoBar::GetButtonLabel(InfoBarButton button) const {
[email protected]70b1f802011-01-26 23:58:58135 DCHECK_EQ(BUTTON_OK, button);
[email protected]f4f50ef2011-01-21 19:01:19136 return l10n_util::GetStringUTF16(
137 IDS_OMNIBOX_SEARCH_HINT_INFOBAR_BUTTON_LABEL);
138}
139
140bool HintInfoBar::Accept() {
141 action_taken_ = true;
142 UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.ShowMe", 1);
143 omnibox_hint_->DisableHint();
144 omnibox_hint_->ShowEnteringQuery();
145 return true;
146}
147
148
149// OmniboxSearchHint ----------------------------------------------------------
150
[email protected]7abc95292011-05-18 00:18:09151OmniboxSearchHint::OmniboxSearchHint(TabContentsWrapper* tab) : tab_(tab) {
[email protected]c8865482009-07-23 20:40:10152 NavigationController* controller = &(tab->controller());
153 notification_registrar_.Add(this,
[email protected]432115822011-07-10 15:52:27154 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
[email protected]c8865482009-07-23 20:40:10155 Source<NavigationController>(controller));
156 // Fill the search_engine_urls_ map, used for faster look-up (overkill?).
[email protected]cfd03402011-09-23 19:27:18157 for (size_t i = 0; i < arraysize(kSearchEngineURLs); ++i)
[email protected]c8865482009-07-23 20:40:10158 search_engine_urls_[kSearchEngineURLs[i]] = 1;
[email protected]c8865482009-07-23 20:40:10159
160 // Listen for omnibox to figure-out when the user searches from the omnibox.
161 notification_registrar_.Add(this,
[email protected]432115822011-07-10 15:52:27162 chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
[email protected]c8865482009-07-23 20:40:10163 Source<Profile>(tab->profile()));
164}
165
166OmniboxSearchHint::~OmniboxSearchHint() {
167}
168
[email protected]432115822011-07-10 15:52:27169void OmniboxSearchHint::Observe(int type,
[email protected]c8865482009-07-23 20:40:10170 const NotificationSource& source,
171 const NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:27172 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) {
[email protected]c8865482009-07-23 20:40:10173 NavigationEntry* entry = tab_->controller().GetActiveEntry();
174 if (search_engine_urls_.find(entry->url().spec()) ==
175 search_engine_urls_.end()) {
176 // The search engine is not in our white-list, bail.
177 return;
178 }
179 const TemplateURL* const default_provider =
[email protected]8e5c89a2011-06-07 18:13:33180 TemplateURLServiceFactory::GetForProfile(tab_->profile())->
181 GetDefaultSearchProvider();
[email protected]c8865482009-07-23 20:40:10182 if (!default_provider)
183 return;
184
185 const TemplateURLRef* const search_url = default_provider->url();
186 if (search_url->GetHost() == entry->url().host())
187 ShowInfoBar();
[email protected]432115822011-07-10 15:52:27188 } else if (type == chrome::NOTIFICATION_OMNIBOX_OPENED_URL) {
[email protected]c8865482009-07-23 20:40:10189 AutocompleteLog* log = Details<AutocompleteLog>(details).ptr();
190 AutocompleteMatch::Type type =
191 log->result.match_at(log->selected_index).type;
192 if (type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED ||
193 type == AutocompleteMatch::SEARCH_HISTORY ||
194 type == AutocompleteMatch::SEARCH_SUGGEST) {
195 // The user performed a search from the omnibox, don't show the infobar
196 // again.
197 DisableHint();
198 }
199 }
200}
201
202void OmniboxSearchHint::ShowInfoBar() {
[email protected]7e204122011-09-01 18:56:21203 tab_->infobar_tab_helper()->AddInfoBar(new HintInfoBar(this));
[email protected]c8865482009-07-23 20:40:10204}
205
206void OmniboxSearchHint::ShowEnteringQuery() {
[email protected]d30f7902011-06-17 02:06:05207 LocationBar* location_bar = BrowserList::GetLastActiveWithProfile(
208 tab_->profile())->window()->GetLocationBar();
[email protected]b76ac712011-05-03 22:17:11209 OmniboxView* omnibox_view = location_bar->location_entry();
[email protected]a26dc362010-04-23 01:48:58210 location_bar->FocusLocation(true);
[email protected]b76ac712011-05-03 22:17:11211 omnibox_view->SetUserText(
[email protected]a2fedb1e2011-01-25 15:23:36212 l10n_util::GetStringUTF16(IDS_OMNIBOX_SEARCH_HINT_OMNIBOX_TEXT));
[email protected]b76ac712011-05-03 22:17:11213 omnibox_view->SelectAll(false);
214 // Entering text in the omnibox view triggers the suggestion popup that we
215 // don't want to show in this case.
216 omnibox_view->ClosePopup();
[email protected]c8865482009-07-23 20:40:10217}
218
219void OmniboxSearchHint::DisableHint() {
220 // The NAV_ENTRY_COMMITTED notification was needed to show the infobar, the
221 // OMNIBOX_OPENED_URL notification was there to set the kShowOmniboxSearchHint
222 // prefs to false, none of them are needed anymore.
223 notification_registrar_.RemoveAll();
224 tab_->profile()->GetPrefs()->SetBoolean(prefs::kShowOmniboxSearchHint,
225 false);
226}
227
228// static
229bool OmniboxSearchHint::IsEnabled(Profile* profile) {
230 // The infobar can only be shown if the correct switch has been provided and
231 // the user did not dismiss the infobar before.
232 return profile->GetPrefs()->GetBoolean(prefs::kShowOmniboxSearchHint) &&
233 CommandLine::ForCurrentProcess()->HasSwitch(
234 switches::kSearchInOmniboxHint);
235}