1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "athena/main/url_search_provider.h"
7 #include "athena/activity/public/activity.h"
8 #include "athena/activity/public/activity_factory.h"
9 #include "athena/content/public/scheme_classifier_factory.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "components/metrics/proto/omnibox_event.pb.h"
13 #include "components/metrics/proto/omnibox_input_type.pb.h"
14 #include "components/omnibox/autocomplete_input.h"
15 #include "components/omnibox/autocomplete_provider_client.h"
16 #include "components/omnibox/search_provider.h"
17 #include "components/search_engines/search_terms_data.h"
18 #include "components/search_engines/template_url_service.h"
19 #include "components/search_engines/template_url_service_client.h"
20 #include "content/public/browser/browser_context.h"
21 #include "ui/app_list/search_result.h"
22 #include "ui/base/resource/resource_bundle.h"
29 // This constant was copied from HistoryURLProvider.
30 // TODO(hashimoto): Componentize HistoryURLProvider and delete this.
31 const int kScoreForWhatYouTypedResult
= 1203;
33 // The SearchTermsData implementation for Athena.
34 class AthenaSearchTermsData
: public SearchTermsData
{
37 virtual std::string
GetSuggestClient() const OVERRIDE
{
42 // The templateURLServiceClient for Athena. Mainly for the interaction with
43 // history module (see chrome/browser/search_engines for Chrome implementation).
44 // TODO(mukai): Implement the contents of this class when it's necessary.
45 class AthenaTemplateURLServiceClient
: public TemplateURLServiceClient
{
47 AthenaTemplateURLServiceClient() {}
48 virtual ~AthenaTemplateURLServiceClient() {}
51 // TemplateURLServiceClient:
52 virtual void SetOwner(TemplateURLService
* owner
) OVERRIDE
{}
53 virtual void DeleteAllSearchTermsForKeyword(TemplateURLID id
) OVERRIDE
{}
54 virtual void SetKeywordSearchTermsForURL(
57 const base::string16
& term
) OVERRIDE
{}
58 virtual void AddKeywordGeneratedVisit(const GURL
& url
) OVERRIDE
{}
59 virtual void RestoreExtensionInfoIfNecessary(
60 TemplateURL
* template_url
) OVERRIDE
{}
62 DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient
);
65 // The AutocompleteProviderClient for Athena.
66 class AthenaAutocompleteProviderClient
: public AutocompleteProviderClient
{
68 explicit AthenaAutocompleteProviderClient(
69 content::BrowserContext
* browser_context
)
70 : browser_context_(browser_context
),
71 scheme_classifier_(CreateSchemeClassifier(browser_context
)) {}
72 virtual ~AthenaAutocompleteProviderClient() {}
74 virtual net::URLRequestContextGetter
* RequestContext() OVERRIDE
{
75 return browser_context_
->GetRequestContext();
77 virtual bool IsOffTheRecord() OVERRIDE
{
78 return browser_context_
->IsOffTheRecord();
80 virtual std::string
AcceptLanguages() OVERRIDE
{
81 // TODO(hashimoto): Return the value stored in the prefs.
84 virtual bool SearchSuggestEnabled() OVERRIDE
{ return true; }
85 virtual bool ShowBookmarkBar() OVERRIDE
{ return false; }
86 virtual const AutocompleteSchemeClassifier
& SchemeClassifier() OVERRIDE
{
87 return *scheme_classifier_
;
89 virtual void Classify(
90 const base::string16
& text
,
92 bool allow_exact_keyword_match
,
93 metrics::OmniboxEventProto::PageClassification page_classification
,
94 AutocompleteMatch
* match
,
95 GURL
* alternate_nav_url
) OVERRIDE
{}
96 virtual history::URLDatabase
* InMemoryDatabase() OVERRIDE
{ return NULL
; }
97 virtual void DeleteMatchingURLsForKeywordFromHistory(
98 history::KeywordID keyword_id
,
99 const base::string16
& term
) OVERRIDE
{}
100 virtual bool TabSyncEnabledAndUnencrypted() OVERRIDE
{ return false; }
101 virtual void PrefetchImage(const GURL
& url
) OVERRIDE
{}
104 content::BrowserContext
* browser_context_
;
105 scoped_ptr
<AutocompleteSchemeClassifier
> scheme_classifier_
;
107 DISALLOW_COPY_AND_ASSIGN(AthenaAutocompleteProviderClient
);
110 int ACMatchStyleToTagStyle(int styles
) {
112 if (styles
& ACMatchClassification::URL
)
113 tag_styles
|= app_list::SearchResult::Tag::URL
;
114 if (styles
& ACMatchClassification::MATCH
)
115 tag_styles
|= app_list::SearchResult::Tag::MATCH
;
116 if (styles
& ACMatchClassification::DIM
)
117 tag_styles
|= app_list::SearchResult::Tag::DIM
;
122 // Translates ACMatchClassifications into SearchResult tags.
123 void ACMatchClassificationsToTags(
124 const base::string16
& text
,
125 const ACMatchClassifications
& text_classes
,
126 app_list::SearchResult::Tags
* tags
) {
127 int tag_styles
= app_list::SearchResult::Tag::NONE
;
128 size_t tag_start
= 0;
130 for (size_t i
= 0; i
< text_classes
.size(); ++i
) {
131 const ACMatchClassification
& text_class
= text_classes
[i
];
133 // Closes current tag.
134 if (tag_styles
!= app_list::SearchResult::Tag::NONE
) {
135 tags
->push_back(app_list::SearchResult::Tag(
136 tag_styles
, tag_start
, text_class
.offset
));
137 tag_styles
= app_list::SearchResult::Tag::NONE
;
140 if (text_class
.style
== ACMatchClassification::NONE
)
143 tag_start
= text_class
.offset
;
144 tag_styles
= ACMatchStyleToTagStyle(text_class
.style
);
147 if (tag_styles
!= app_list::SearchResult::Tag::NONE
) {
148 tags
->push_back(app_list::SearchResult::Tag(
149 tag_styles
, tag_start
, text
.length()));
153 class UrlSearchResult
: public app_list::SearchResult
{
155 UrlSearchResult(content::BrowserContext
* browser_context
,
156 const AutocompleteMatch
& match
)
157 : browser_context_(browser_context
),
159 set_id(match_
.destination_url
.spec());
161 // Derive relevance from omnibox relevance and normalize it to [0, 1].
162 // The magic number 1500 is the highest score of an omnibox result.
163 // See comments in autocomplete_provider.h.
164 set_relevance(match_
.relevance
/ 1500.0);
167 UpdateTitleAndDetails();
170 virtual ~UrlSearchResult() {}
173 // Overriddenn from app_list::SearchResult:
174 virtual void Open(int event_flags
) OVERRIDE
{
175 Activity
* activity
= ActivityFactory::Get()->CreateWebActivity(
176 browser_context_
, base::string16(), match_
.destination_url
);
177 Activity::Show(activity
);
181 SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
182 AutocompleteMatch::TypeToIcon(match_
.type
)));
185 void UpdateTitleAndDetails() {
186 set_title(match_
.contents
);
187 SearchResult::Tags title_tags
;
188 ACMatchClassificationsToTags(match_
.contents
,
189 match_
.contents_class
,
191 set_title_tags(title_tags
);
193 set_details(match_
.description
);
194 SearchResult::Tags details_tags
;
195 ACMatchClassificationsToTags(match_
.description
,
196 match_
.description_class
,
198 set_details_tags(details_tags
);
201 content::BrowserContext
* browser_context_
;
202 AutocompleteMatch match_
;
204 DISALLOW_COPY_AND_ASSIGN(UrlSearchResult
);
209 UrlSearchProvider::UrlSearchProvider(content::BrowserContext
* browser_context
)
210 : browser_context_(browser_context
),
211 // TODO(mukai): introduce the real parameters when it's necessary.
212 template_url_service_(
213 new TemplateURLService(NULL
/* prefs */,
214 scoped_ptr
<SearchTermsData
>(
215 new AthenaSearchTermsData()),
216 NULL
/* KeywordWebDataService */,
217 scoped_ptr
<TemplateURLServiceClient
>(
218 new AthenaTemplateURLServiceClient()),
219 NULL
/*GoogleURLTracker */,
220 NULL
/* RapporService */,
221 base::Closure() /* dsp_change_callback */)),
222 provider_(new ::SearchProvider(
224 template_url_service_
.get(),
225 scoped_ptr
<AutocompleteProviderClient
>(
226 new AthenaAutocompleteProviderClient(browser_context_
)))) {
227 template_url_service_
->Load();
230 UrlSearchProvider::~UrlSearchProvider() {
233 void UrlSearchProvider::Start(const base::string16
& query
) {
234 const bool minimal_changes
= query
== input_
.text();
235 scoped_ptr
<AutocompleteSchemeClassifier
> scheme_classifier(
236 CreateSchemeClassifier(browser_context_
));
237 input_
= AutocompleteInput(query
,
238 base::string16::npos
/* cursor_position */,
239 base::string16() /* desired_tld */,
240 GURL() /* current_url */,
241 metrics::OmniboxEventProto::INVALID_SPEC
,
242 false /* prevent_inline_autocomplete */,
243 false /* prefer_keyword */,
244 true /* allow_extract_keyword_match */,
245 true /* want_asynchronous_matches */,
248 // Clearing results here may cause unexpected results.
249 // TODO(mukai): fix this by fixing crbug.com/415500
250 if (!minimal_changes
)
253 if (input_
.type() == metrics::OmniboxInputType::URL
) {
254 // TODO(hashimoto): Componentize HistoryURLProvider and remove this code.
255 AutocompleteMatch
what_you_typed_match(
256 NULL
, 0, false, AutocompleteMatchType::URL_WHAT_YOU_TYPED
);
257 what_you_typed_match
.destination_url
= input_
.canonicalized_url();
258 what_you_typed_match
.contents
= input_
.text();
259 what_you_typed_match
.relevance
= kScoreForWhatYouTypedResult
;
260 Add(scoped_ptr
<app_list::SearchResult
>(new UrlSearchResult(
261 browser_context_
, what_you_typed_match
)));
264 provider_
->Start(input_
, minimal_changes
);
267 void UrlSearchProvider::Stop() {
268 provider_
->Stop(false);
271 void UrlSearchProvider::OnProviderUpdate(bool updated_matches
) {
272 if (!updated_matches
)
275 const ACMatches
& matches
= provider_
->matches();
276 for (ACMatches::const_iterator it
= matches
.begin(); it
!= matches
.end();
278 if (!it
->destination_url
.is_valid())
281 Add(scoped_ptr
<app_list::SearchResult
>(new UrlSearchResult(
282 browser_context_
, *it
)));
286 } // namespace athena