• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "athena/main/url_search_provider.h"
6 
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"
23 #include "url/gurl.h"
24 
25 namespace athena {
26 
27 namespace {
28 
29 // This constant was copied from HistoryURLProvider.
30 // TODO(hashimoto): Componentize HistoryURLProvider and delete this.
31 const int kScoreForWhatYouTypedResult = 1203;
32 
33 // The SearchTermsData implementation for Athena.
34 class AthenaSearchTermsData : public SearchTermsData {
35  public:
36   // SearchTermsData:
GetSuggestClient() const37   virtual std::string GetSuggestClient() const OVERRIDE {
38     return "chrome";
39   }
40 };
41 
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 {
46  public:
AthenaTemplateURLServiceClient()47   AthenaTemplateURLServiceClient() {}
~AthenaTemplateURLServiceClient()48   virtual ~AthenaTemplateURLServiceClient() {}
49 
50  private:
51   // TemplateURLServiceClient:
SetOwner(TemplateURLService * owner)52   virtual void SetOwner(TemplateURLService* owner) OVERRIDE {}
DeleteAllSearchTermsForKeyword(TemplateURLID id)53   virtual void DeleteAllSearchTermsForKeyword(TemplateURLID id) OVERRIDE {}
SetKeywordSearchTermsForURL(const GURL & url,TemplateURLID id,const base::string16 & term)54   virtual void SetKeywordSearchTermsForURL(
55       const GURL& url,
56       TemplateURLID id,
57       const base::string16& term) OVERRIDE {}
AddKeywordGeneratedVisit(const GURL & url)58   virtual void AddKeywordGeneratedVisit(const GURL& url) OVERRIDE {}
RestoreExtensionInfoIfNecessary(TemplateURL * template_url)59   virtual void RestoreExtensionInfoIfNecessary(
60       TemplateURL* template_url) OVERRIDE {}
61 
62   DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient);
63 };
64 
65 // The AutocompleteProviderClient for Athena.
66 class AthenaAutocompleteProviderClient : public AutocompleteProviderClient {
67  public:
AthenaAutocompleteProviderClient(content::BrowserContext * browser_context)68   explicit AthenaAutocompleteProviderClient(
69       content::BrowserContext* browser_context)
70       : browser_context_(browser_context),
71         scheme_classifier_(CreateSchemeClassifier(browser_context)) {}
~AthenaAutocompleteProviderClient()72   virtual ~AthenaAutocompleteProviderClient() {}
73 
RequestContext()74   virtual net::URLRequestContextGetter* RequestContext() OVERRIDE {
75     return browser_context_->GetRequestContext();
76   }
IsOffTheRecord()77   virtual bool IsOffTheRecord() OVERRIDE {
78     return browser_context_->IsOffTheRecord();
79   }
AcceptLanguages()80   virtual std::string AcceptLanguages() OVERRIDE {
81     // TODO(hashimoto): Return the value stored in the prefs.
82     return "en-US";
83   }
SearchSuggestEnabled()84   virtual bool SearchSuggestEnabled() OVERRIDE { return true; }
ShowBookmarkBar()85   virtual bool ShowBookmarkBar() OVERRIDE { return false; }
SchemeClassifier()86   virtual const AutocompleteSchemeClassifier& SchemeClassifier() OVERRIDE {
87     return *scheme_classifier_;
88   }
Classify(const base::string16 & text,bool prefer_keyword,bool allow_exact_keyword_match,metrics::OmniboxEventProto::PageClassification page_classification,AutocompleteMatch * match,GURL * alternate_nav_url)89   virtual void Classify(
90       const base::string16& text,
91       bool prefer_keyword,
92       bool allow_exact_keyword_match,
93       metrics::OmniboxEventProto::PageClassification page_classification,
94       AutocompleteMatch* match,
95       GURL* alternate_nav_url) OVERRIDE {}
InMemoryDatabase()96   virtual history::URLDatabase* InMemoryDatabase() OVERRIDE { return NULL; }
DeleteMatchingURLsForKeywordFromHistory(history::KeywordID keyword_id,const base::string16 & term)97   virtual void DeleteMatchingURLsForKeywordFromHistory(
98       history::KeywordID keyword_id,
99       const base::string16& term) OVERRIDE {}
TabSyncEnabledAndUnencrypted()100   virtual bool TabSyncEnabledAndUnencrypted() OVERRIDE { return false; }
PrefetchImage(const GURL & url)101   virtual void PrefetchImage(const GURL& url) OVERRIDE {}
102 
103  private:
104   content::BrowserContext* browser_context_;
105   scoped_ptr<AutocompleteSchemeClassifier> scheme_classifier_;
106 
107   DISALLOW_COPY_AND_ASSIGN(AthenaAutocompleteProviderClient);
108 };
109 
ACMatchStyleToTagStyle(int styles)110 int ACMatchStyleToTagStyle(int styles) {
111   int tag_styles = 0;
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;
118 
119   return tag_styles;
120 }
121 
122 // Translates ACMatchClassifications into SearchResult tags.
ACMatchClassificationsToTags(const base::string16 & text,const ACMatchClassifications & text_classes,app_list::SearchResult::Tags * 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;
129 
130   for (size_t i = 0; i < text_classes.size(); ++i) {
131     const ACMatchClassification& text_class = text_classes[i];
132 
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;
138     }
139 
140     if (text_class.style == ACMatchClassification::NONE)
141       continue;
142 
143     tag_start = text_class.offset;
144     tag_styles = ACMatchStyleToTagStyle(text_class.style);
145   }
146 
147   if (tag_styles != app_list::SearchResult::Tag::NONE) {
148     tags->push_back(app_list::SearchResult::Tag(
149         tag_styles, tag_start, text.length()));
150   }
151 }
152 
153 class UrlSearchResult : public app_list::SearchResult {
154  public:
UrlSearchResult(content::BrowserContext * browser_context,const AutocompleteMatch & match)155   UrlSearchResult(content::BrowserContext* browser_context,
156                   const AutocompleteMatch& match)
157       : browser_context_(browser_context),
158         match_(match) {
159     set_id(match_.destination_url.spec());
160 
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);
165 
166     UpdateIcon();
167     UpdateTitleAndDetails();
168   }
169 
~UrlSearchResult()170   virtual ~UrlSearchResult() {}
171 
172  private:
173   // Overriddenn from app_list::SearchResult:
Open(int event_flags)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);
178   }
179 
UpdateIcon()180   void UpdateIcon() {
181     SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
182         AutocompleteMatch::TypeToIcon(match_.type)));
183   }
184 
UpdateTitleAndDetails()185   void UpdateTitleAndDetails() {
186     set_title(match_.contents);
187     SearchResult::Tags title_tags;
188     ACMatchClassificationsToTags(match_.contents,
189                                  match_.contents_class,
190                                  &title_tags);
191     set_title_tags(title_tags);
192 
193     set_details(match_.description);
194     SearchResult::Tags details_tags;
195     ACMatchClassificationsToTags(match_.description,
196                                  match_.description_class,
197                                  &details_tags);
198     set_details_tags(details_tags);
199   }
200 
201   content::BrowserContext* browser_context_;
202   AutocompleteMatch match_;
203 
204   DISALLOW_COPY_AND_ASSIGN(UrlSearchResult);
205 };
206 
207 }  // namespace
208 
UrlSearchProvider(content::BrowserContext * browser_context)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(
223           this,
224           template_url_service_.get(),
225           scoped_ptr<AutocompleteProviderClient>(
226               new AthenaAutocompleteProviderClient(browser_context_)))) {
227   template_url_service_->Load();
228 }
229 
~UrlSearchProvider()230 UrlSearchProvider::~UrlSearchProvider() {
231 }
232 
Start(const base::string16 & query)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 */,
246                              *scheme_classifier);
247 
248   // Clearing results here may cause unexpected results.
249   // TODO(mukai): fix this by fixing crbug.com/415500
250   if (!minimal_changes)
251     ClearResults();
252 
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)));
262   }
263 
264   provider_->Start(input_, minimal_changes);
265 }
266 
Stop()267 void UrlSearchProvider::Stop() {
268   provider_->Stop(false);
269 }
270 
OnProviderUpdate(bool updated_matches)271 void UrlSearchProvider::OnProviderUpdate(bool updated_matches) {
272   if (!updated_matches)
273     return;
274 
275   const ACMatches& matches = provider_->matches();
276   for (ACMatches::const_iterator it = matches.begin(); it != matches.end();
277        ++it) {
278     if (!it->destination_url.is_valid())
279       continue;
280 
281     Add(scoped_ptr<app_list::SearchResult>(new UrlSearchResult(
282         browser_context_, *it)));
283   }
284 }
285 
286 }  // namespace athena
287