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/extensions/shell/url_search_provider.h"
7 #include "athena/activity/public/activity.h"
8 #include "athena/activity/public/activity_factory.h"
9 #include "athena/extensions/shell/athena_shell_scheme_classifier.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
{ return "chrome"; }
40 // The templateURLServiceClient for Athena. Mainly for the interaction with
41 // history module (see chrome/browser/search_engines for Chrome implementation).
42 // TODO(mukai): Implement the contents of this class when it's necessary.
43 class AthenaTemplateURLServiceClient
: public TemplateURLServiceClient
{
45 AthenaTemplateURLServiceClient() {}
46 ~AthenaTemplateURLServiceClient() override
{}
49 // TemplateURLServiceClient:
50 void Shutdown() override
{}
51 void SetOwner(TemplateURLService
* owner
) override
{}
52 void DeleteAllSearchTermsForKeyword(TemplateURLID id
) override
{}
53 void SetKeywordSearchTermsForURL(const GURL
& url
,
55 const base::string16
& term
) override
{}
56 void AddKeywordGeneratedVisit(const GURL
& url
) override
{}
57 void RestoreExtensionInfoIfNecessary(TemplateURL
* template_url
) override
{}
59 DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient
);
62 // The AutocompleteProviderClient for Athena.
63 class AthenaAutocompleteProviderClient
: public AutocompleteProviderClient
{
65 explicit AthenaAutocompleteProviderClient(
66 content::BrowserContext
* browser_context
)
67 : browser_context_(browser_context
) {}
68 ~AthenaAutocompleteProviderClient() override
{}
70 net::URLRequestContextGetter
* RequestContext() override
{
71 return browser_context_
->GetRequestContext();
73 bool IsOffTheRecord() override
{ return browser_context_
->IsOffTheRecord(); }
74 std::string
AcceptLanguages() override
{
75 // TODO(hashimoto): Return the value stored in the prefs.
78 bool SearchSuggestEnabled() override
{ return true; }
79 bool ShowBookmarkBar() override
{ return false; }
80 const AutocompleteSchemeClassifier
& SchemeClassifier() override
{
81 return scheme_classifier_
;
84 const base::string16
& text
,
86 bool allow_exact_keyword_match
,
87 metrics::OmniboxEventProto::PageClassification page_classification
,
88 AutocompleteMatch
* match
,
89 GURL
* alternate_nav_url
) override
{}
90 history::URLDatabase
* InMemoryDatabase() override
{ return nullptr; }
91 void DeleteMatchingURLsForKeywordFromHistory(
92 history::KeywordID keyword_id
,
93 const base::string16
& term
) override
{}
94 bool TabSyncEnabledAndUnencrypted() override
{ return false; }
95 void PrefetchImage(const GURL
& url
) override
{}
98 content::BrowserContext
* browser_context_
;
99 AthenaShellSchemeClassifier scheme_classifier_
;
101 DISALLOW_COPY_AND_ASSIGN(AthenaAutocompleteProviderClient
);
104 int ACMatchStyleToTagStyle(int styles
) {
106 if (styles
& ACMatchClassification::URL
)
107 tag_styles
|= app_list::SearchResult::Tag::URL
;
108 if (styles
& ACMatchClassification::MATCH
)
109 tag_styles
|= app_list::SearchResult::Tag::MATCH
;
110 if (styles
& ACMatchClassification::DIM
)
111 tag_styles
|= app_list::SearchResult::Tag::DIM
;
116 // Translates ACMatchClassifications into SearchResult tags.
117 void ACMatchClassificationsToTags(const base::string16
& text
,
118 const ACMatchClassifications
& text_classes
,
119 app_list::SearchResult::Tags
* tags
) {
120 int tag_styles
= app_list::SearchResult::Tag::NONE
;
121 size_t tag_start
= 0;
123 for (size_t i
= 0; i
< text_classes
.size(); ++i
) {
124 const ACMatchClassification
& text_class
= text_classes
[i
];
126 // Closes current tag.
127 if (tag_styles
!= app_list::SearchResult::Tag::NONE
) {
128 tags
->push_back(app_list::SearchResult::Tag(
129 tag_styles
, tag_start
, text_class
.offset
));
130 tag_styles
= app_list::SearchResult::Tag::NONE
;
133 if (text_class
.style
== ACMatchClassification::NONE
)
136 tag_start
= text_class
.offset
;
137 tag_styles
= ACMatchStyleToTagStyle(text_class
.style
);
140 if (tag_styles
!= app_list::SearchResult::Tag::NONE
) {
142 app_list::SearchResult::Tag(tag_styles
, tag_start
, text
.length()));
146 class UrlSearchResult
: public app_list::SearchResult
{
148 UrlSearchResult(content::BrowserContext
* browser_context
,
149 const AutocompleteMatch
& match
)
150 : browser_context_(browser_context
), match_(match
) {
151 set_id(match_
.destination_url
.spec());
153 // Derive relevance from omnibox relevance and normalize it to [0, 1].
154 // The magic number 1500 is the highest score of an omnibox result.
155 // See comments in autocomplete_provider.h.
156 set_relevance(match_
.relevance
/ 1500.0);
159 UpdateTitleAndDetails();
162 ~UrlSearchResult() override
{}
165 // Overridden from app_list::SearchResult:
166 scoped_ptr
<app_list::SearchResult
> Duplicate() override
{
167 return make_scoped_ptr(new UrlSearchResult(browser_context_
, match_
));
170 void Open(int event_flags
) override
{
171 Activity
* activity
= ActivityFactory::Get()->CreateWebActivity(
172 browser_context_
, base::string16(), match_
.destination_url
);
173 Activity::Show(activity
);
177 SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
178 AutocompleteMatch::TypeToIcon(match_
.type
)));
181 void UpdateTitleAndDetails() {
182 set_title(match_
.contents
);
183 SearchResult::Tags title_tags
;
184 ACMatchClassificationsToTags(
185 match_
.contents
, match_
.contents_class
, &title_tags
);
186 set_title_tags(title_tags
);
188 set_details(match_
.description
);
189 SearchResult::Tags details_tags
;
190 ACMatchClassificationsToTags(
191 match_
.description
, match_
.description_class
, &details_tags
);
192 set_details_tags(details_tags
);
195 content::BrowserContext
* browser_context_
;
196 AutocompleteMatch match_
;
198 DISALLOW_COPY_AND_ASSIGN(UrlSearchResult
);
203 UrlSearchProvider::UrlSearchProvider(content::BrowserContext
* browser_context
)
204 : browser_context_(browser_context
),
205 // TODO(mukai): introduce the real parameters when it's necessary.
206 template_url_service_(new TemplateURLService(
208 scoped_ptr
<SearchTermsData
>(new AthenaSearchTermsData()),
209 nullptr /* KeywordWebDataService */,
210 scoped_ptr
<TemplateURLServiceClient
>(
211 new AthenaTemplateURLServiceClient()),
212 nullptr /*GoogleURLTracker */,
213 nullptr /* RapporService */,
214 base::Closure() /* dsp_change_callback */)),
215 provider_(new ::SearchProvider(
217 template_url_service_
.get(),
218 scoped_ptr
<AutocompleteProviderClient
>(
219 new AthenaAutocompleteProviderClient(browser_context_
)))) {
220 template_url_service_
->Load();
223 UrlSearchProvider::~UrlSearchProvider() {
226 void UrlSearchProvider::Start(const base::string16
& query
) {
227 const bool minimal_changes
= query
== input_
.text();
228 input_
= AutocompleteInput(query
,
229 base::string16::npos
/* cursor_position */,
230 std::string() /* desired_tld */,
231 GURL() /* current_url */,
232 metrics::OmniboxEventProto::INVALID_SPEC
,
233 false /* prevent_inline_autocomplete */,
234 false /* prefer_keyword */,
235 true /* allow_extract_keyword_match */,
236 true /* want_asynchronous_matches */,
237 AthenaShellSchemeClassifier());
239 // Clearing results here may cause unexpected results.
240 // TODO(mukai): fix this by fixing crbug.com/415500
241 if (!minimal_changes
)
244 if (input_
.type() == metrics::OmniboxInputType::URL
) {
245 // TODO(hashimoto): Componentize HistoryURLProvider and remove this code.
246 AutocompleteMatch
what_you_typed_match(
247 nullptr, 0, false, AutocompleteMatchType::URL_WHAT_YOU_TYPED
);
248 what_you_typed_match
.destination_url
= input_
.canonicalized_url();
249 what_you_typed_match
.contents
= input_
.text();
250 what_you_typed_match
.relevance
= kScoreForWhatYouTypedResult
;
251 Add(scoped_ptr
<app_list::SearchResult
>(
252 new UrlSearchResult(browser_context_
, what_you_typed_match
)));
255 provider_
->Start(input_
, minimal_changes
);
258 void UrlSearchProvider::Stop() {
259 provider_
->Stop(false);
262 void UrlSearchProvider::OnProviderUpdate(bool updated_matches
) {
263 if (!updated_matches
)
266 const ACMatches
& matches
= provider_
->matches();
267 for (ACMatches::const_iterator it
= matches
.begin(); it
!= matches
.end();
269 if (!it
->destination_url
.is_valid())
272 Add(scoped_ptr
<app_list::SearchResult
>(
273 new UrlSearchResult(browser_context_
, *it
)));
277 } // namespace athena