• 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 "chrome/browser/android/omnibox/autocomplete_controller_android.h"
6 
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h"
13 #include "base/timer/timer.h"
14 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
15 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
16 #include "chrome/browser/autocomplete/autocomplete_controller.h"
17 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
18 #include "chrome/browser/autocomplete/shortcuts_backend_factory.h"
19 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/omnibox/omnibox_log.h"
23 #include "chrome/browser/profiles/incognito_helpers.h"
24 #include "chrome/browser/profiles/profile_android.h"
25 #include "chrome/browser/profiles/profile_manager.h"
26 #include "chrome/browser/search/search.h"
27 #include "chrome/browser/search_engines/template_url_service_factory.h"
28 #include "chrome/browser/sessions/session_tab_helper.h"
29 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
30 #include "chrome/browser/ui/toolbar/toolbar_model.h"
31 #include "chrome/common/instant_types.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h"
34 #include "components/bookmarks/browser/bookmark_model.h"
35 #include "components/keyed_service/content/browser_context_dependency_manager.h"
36 #include "components/metrics/proto/omnibox_event.pb.h"
37 #include "components/omnibox/autocomplete_input.h"
38 #include "components/omnibox/autocomplete_match.h"
39 #include "components/omnibox/autocomplete_match_type.h"
40 #include "components/omnibox/omnibox_field_trial.h"
41 #include "components/omnibox/search_provider.h"
42 #include "components/search/search.h"
43 #include "components/search_engines/template_url_service.h"
44 #include "content/public/browser/notification_details.h"
45 #include "content/public/browser/notification_service.h"
46 #include "content/public/browser/notification_source.h"
47 #include "content/public/browser/web_contents.h"
48 #include "content/public/common/url_constants.h"
49 #include "jni/AutocompleteController_jni.h"
50 #include "net/base/escape.h"
51 #include "net/base/net_util.h"
52 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
53 
54 using base::android::AttachCurrentThread;
55 using base::android::ConvertJavaStringToUTF16;
56 using base::android::ConvertUTF8ToJavaString;
57 using base::android::ConvertUTF16ToJavaString;
58 using metrics::OmniboxEventProto;
59 
60 namespace {
61 
62 const int kAndroidAutocompleteProviders =
63     AutocompleteClassifier::kDefaultOmniboxProviders;
64 
65 /**
66  * A prefetcher class responsible for triggering zero suggest prefetch.
67  * The prefetch occurs as a side-effect of calling StartZeroSuggest() on
68  * the AutocompleteController object.
69  */
70 class ZeroSuggestPrefetcher : public AutocompleteControllerDelegate {
71  public:
72   explicit ZeroSuggestPrefetcher(Profile* profile);
73 
74  private:
75   virtual ~ZeroSuggestPrefetcher();
76   void SelfDestruct();
77 
78   // AutocompleteControllerDelegate:
79   virtual void OnResultChanged(bool default_match_changed) OVERRIDE;
80 
81   scoped_ptr<AutocompleteController> controller_;
82   base::OneShotTimer<ZeroSuggestPrefetcher> expire_timer_;
83 };
84 
ZeroSuggestPrefetcher(Profile * profile)85 ZeroSuggestPrefetcher::ZeroSuggestPrefetcher(Profile* profile)
86     : controller_(new AutocompleteController(
87           profile, TemplateURLServiceFactory::GetForProfile(profile), this,
88           AutocompleteProvider::TYPE_ZERO_SUGGEST)) {
89   // Creating an arbitrary fake_request_source to avoid passing in an invalid
90   // AutocompleteInput object.
91   base::string16 fake_request_source(base::ASCIIToUTF16(
92       "http://www.foobarbazblah.com"));
93   controller_->StartZeroSuggest(AutocompleteInput(
94       fake_request_source, base::string16::npos, base::string16(),
95       GURL(fake_request_source), OmniboxEventProto::INVALID_SPEC, false, false,
96       true, true, ChromeAutocompleteSchemeClassifier(profile)));
97   // Delete ourselves after 10s. This is enough time to cache results or
98   // give up if the results haven't been received.
99   expire_timer_.Start(FROM_HERE,
100                       base::TimeDelta::FromMilliseconds(10000),
101                       this, &ZeroSuggestPrefetcher::SelfDestruct);
102 }
103 
~ZeroSuggestPrefetcher()104 ZeroSuggestPrefetcher::~ZeroSuggestPrefetcher() {
105 }
106 
SelfDestruct()107 void ZeroSuggestPrefetcher::SelfDestruct() {
108   delete this;
109 }
110 
OnResultChanged(bool default_match_changed)111 void ZeroSuggestPrefetcher::OnResultChanged(bool default_match_changed) {
112   // Nothing to do here, the results have been cached.
113   // We don't want to trigger deletion here because this is being called by the
114   // AutocompleteController object.
115 }
116 
117 }  // namespace
118 
AutocompleteControllerAndroid(Profile * profile)119 AutocompleteControllerAndroid::AutocompleteControllerAndroid(Profile* profile)
120     : autocomplete_controller_(new AutocompleteController(
121           profile, TemplateURLServiceFactory::GetForProfile(profile), this,
122           kAndroidAutocompleteProviders)),
123       inside_synchronous_start_(false),
124       profile_(profile) {
125 }
126 
Start(JNIEnv * env,jobject obj,jstring j_text,jstring j_desired_tld,jstring j_current_url,bool prevent_inline_autocomplete,bool prefer_keyword,bool allow_exact_keyword_match,bool want_asynchronous_matches)127 void AutocompleteControllerAndroid::Start(JNIEnv* env,
128                                           jobject obj,
129                                           jstring j_text,
130                                           jstring j_desired_tld,
131                                           jstring j_current_url,
132                                           bool prevent_inline_autocomplete,
133                                           bool prefer_keyword,
134                                           bool allow_exact_keyword_match,
135                                           bool want_asynchronous_matches) {
136   if (!autocomplete_controller_)
137     return;
138 
139   base::string16 desired_tld;
140   GURL current_url;
141   if (j_current_url != NULL)
142     current_url = GURL(ConvertJavaStringToUTF16(env, j_current_url));
143   if (j_desired_tld != NULL)
144     desired_tld = ConvertJavaStringToUTF16(env, j_desired_tld);
145   base::string16 text = ConvertJavaStringToUTF16(env, j_text);
146   OmniboxEventProto::PageClassification page_classification =
147       OmniboxEventProto::OTHER;
148   input_ = AutocompleteInput(
149       text, base::string16::npos, desired_tld, current_url, page_classification,
150       prevent_inline_autocomplete, prefer_keyword, allow_exact_keyword_match,
151       want_asynchronous_matches, ChromeAutocompleteSchemeClassifier(profile_));
152   autocomplete_controller_->Start(input_);
153 }
154 
Classify(JNIEnv * env,jobject obj,jstring j_text)155 ScopedJavaLocalRef<jobject> AutocompleteControllerAndroid::Classify(
156     JNIEnv* env,
157     jobject obj,
158     jstring j_text) {
159   return GetTopSynchronousResult(env, obj, j_text, true);
160 }
161 
StartZeroSuggest(JNIEnv * env,jobject obj,jstring j_omnibox_text,jstring j_current_url,jboolean is_query_in_omnibox,jboolean focused_from_fakebox)162 void AutocompleteControllerAndroid::StartZeroSuggest(
163     JNIEnv* env,
164     jobject obj,
165     jstring j_omnibox_text,
166     jstring j_current_url,
167     jboolean is_query_in_omnibox,
168     jboolean focused_from_fakebox) {
169   if (!autocomplete_controller_)
170     return;
171 
172   base::string16 url = ConvertJavaStringToUTF16(env, j_current_url);
173   const GURL current_url = GURL(url);
174   base::string16 omnibox_text = ConvertJavaStringToUTF16(env, j_omnibox_text);
175 
176   // If omnibox text is empty, set it to the current URL for the purposes of
177   // populating the verbatim match.
178   if (omnibox_text.empty())
179     omnibox_text = url;
180 
181   input_ = AutocompleteInput(
182       omnibox_text, base::string16::npos, base::string16(), current_url,
183       ClassifyPage(current_url, is_query_in_omnibox, focused_from_fakebox),
184       false, false, true, true, ChromeAutocompleteSchemeClassifier(profile_));
185   autocomplete_controller_->StartZeroSuggest(input_);
186 }
187 
Stop(JNIEnv * env,jobject obj,bool clear_results)188 void AutocompleteControllerAndroid::Stop(JNIEnv* env,
189                                          jobject obj,
190                                          bool clear_results) {
191   if (autocomplete_controller_ != NULL)
192     autocomplete_controller_->Stop(clear_results);
193 }
194 
ResetSession(JNIEnv * env,jobject obj)195 void AutocompleteControllerAndroid::ResetSession(JNIEnv* env, jobject obj) {
196   if (autocomplete_controller_ != NULL)
197     autocomplete_controller_->ResetSession();
198 }
199 
OnSuggestionSelected(JNIEnv * env,jobject obj,jint selected_index,jstring j_current_url,jboolean is_query_in_omnibox,jboolean focused_from_fakebox,jlong elapsed_time_since_first_modified,jobject j_web_contents)200 void AutocompleteControllerAndroid::OnSuggestionSelected(
201     JNIEnv* env,
202     jobject obj,
203     jint selected_index,
204     jstring j_current_url,
205     jboolean is_query_in_omnibox,
206     jboolean focused_from_fakebox,
207     jlong elapsed_time_since_first_modified,
208     jobject j_web_contents) {
209   base::string16 url = ConvertJavaStringToUTF16(env, j_current_url);
210   const GURL current_url = GURL(url);
211   OmniboxEventProto::PageClassification current_page_classification =
212       ClassifyPage(current_url, is_query_in_omnibox, focused_from_fakebox);
213   const base::TimeTicks& now(base::TimeTicks::Now());
214   content::WebContents* web_contents =
215       content::WebContents::FromJavaWebContents(j_web_contents);
216 
217   OmniboxLog log(
218       input_.text(),
219       false, /* don't know */
220       input_.type(),
221       true,
222       selected_index,
223       false,
224       SessionTabHelper::IdForTab(web_contents),
225       current_page_classification,
226       base::TimeDelta::FromMilliseconds(elapsed_time_since_first_modified),
227       base::string16::npos,
228       now - autocomplete_controller_->last_time_default_match_changed(),
229       autocomplete_controller_->result());
230   autocomplete_controller_->AddProvidersInfo(&log.providers_info);
231 
232   content::NotificationService::current()->Notify(
233       chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
234       content::Source<Profile>(profile_),
235       content::Details<OmniboxLog>(&log));
236 }
237 
DeleteSuggestion(JNIEnv * env,jobject obj,int selected_index)238 void AutocompleteControllerAndroid::DeleteSuggestion(JNIEnv* env,
239                                                      jobject obj,
240                                                      int selected_index) {
241   const AutocompleteResult& result = autocomplete_controller_->result();
242   const AutocompleteMatch& match = result.match_at(selected_index);
243   if (match.SupportsDeletion())
244     autocomplete_controller_->DeleteMatch(match);
245 }
246 
247 ScopedJavaLocalRef<jstring> AutocompleteControllerAndroid::
UpdateMatchDestinationURLWithQueryFormulationTime(JNIEnv * env,jobject obj,jint selected_index,jlong elapsed_time_since_input_change)248     UpdateMatchDestinationURLWithQueryFormulationTime(
249         JNIEnv* env,
250         jobject obj,
251         jint selected_index,
252         jlong elapsed_time_since_input_change) {
253   // In rare cases, we navigate to cached matches and the underlying result
254   // has already been cleared, in that case ignore the URL update.
255   if (autocomplete_controller_->result().empty())
256     return ScopedJavaLocalRef<jstring>();
257 
258   AutocompleteMatch match(
259       autocomplete_controller_->result().match_at(selected_index));
260   autocomplete_controller_->UpdateMatchDestinationURLWithQueryFormulationTime(
261       base::TimeDelta::FromMilliseconds(elapsed_time_since_input_change),
262       &match);
263   return ConvertUTF8ToJavaString(env, match.destination_url.spec());
264 }
265 
266 ScopedJavaLocalRef<jobject>
GetTopSynchronousMatch(JNIEnv * env,jobject obj,jstring query)267 AutocompleteControllerAndroid::GetTopSynchronousMatch(JNIEnv* env,
268                                                       jobject obj,
269                                                       jstring query) {
270   return GetTopSynchronousResult(env, obj, query, false);
271 }
272 
Shutdown()273 void AutocompleteControllerAndroid::Shutdown() {
274   autocomplete_controller_.reset();
275 
276   JNIEnv* env = AttachCurrentThread();
277   ScopedJavaLocalRef<jobject> java_bridge =
278       weak_java_autocomplete_controller_android_.get(env);
279   if (java_bridge.obj())
280     Java_AutocompleteController_notifyNativeDestroyed(env, java_bridge.obj());
281 
282   weak_java_autocomplete_controller_android_.reset();
283 }
284 
285 // static
286 AutocompleteControllerAndroid*
GetForProfile(Profile * profile,JNIEnv * env,jobject obj)287 AutocompleteControllerAndroid::Factory::GetForProfile(
288     Profile* profile, JNIEnv* env, jobject obj) {
289   AutocompleteControllerAndroid* bridge =
290       static_cast<AutocompleteControllerAndroid*>(
291           GetInstance()->GetServiceForBrowserContext(profile, true));
292   bridge->InitJNI(env, obj);
293   return bridge;
294 }
295 
296 AutocompleteControllerAndroid::Factory*
GetInstance()297 AutocompleteControllerAndroid::Factory::GetInstance() {
298   return Singleton<AutocompleteControllerAndroid::Factory>::get();
299 }
300 
301 content::BrowserContext*
GetBrowserContextToUse(content::BrowserContext * context) const302 AutocompleteControllerAndroid::Factory::GetBrowserContextToUse(
303     content::BrowserContext* context) const {
304   return chrome::GetBrowserContextOwnInstanceInIncognito(context);
305 }
306 
Factory()307 AutocompleteControllerAndroid::Factory::Factory()
308     : BrowserContextKeyedServiceFactory(
309           "AutocompleteControllerAndroid",
310           BrowserContextDependencyManager::GetInstance()) {
311   DependsOn(ShortcutsBackendFactory::GetInstance());
312 }
313 
~Factory()314 AutocompleteControllerAndroid::Factory::~Factory() {
315 }
316 
BuildServiceInstanceFor(content::BrowserContext * profile) const317 KeyedService* AutocompleteControllerAndroid::Factory::BuildServiceInstanceFor(
318     content::BrowserContext* profile) const {
319   return new AutocompleteControllerAndroid(static_cast<Profile*>(profile));
320 }
321 
~AutocompleteControllerAndroid()322 AutocompleteControllerAndroid::~AutocompleteControllerAndroid() {
323 }
324 
InitJNI(JNIEnv * env,jobject obj)325 void AutocompleteControllerAndroid::InitJNI(JNIEnv* env, jobject obj) {
326   weak_java_autocomplete_controller_android_ =
327       JavaObjectWeakGlobalRef(env, obj);
328 }
329 
OnResultChanged(bool default_match_changed)330 void AutocompleteControllerAndroid::OnResultChanged(
331     bool default_match_changed) {
332   if (!autocomplete_controller_)
333     return;
334 
335   const AutocompleteResult& result = autocomplete_controller_->result();
336   const AutocompleteResult::const_iterator default_match(
337       result.default_match());
338   if ((default_match != result.end()) && default_match_changed &&
339       chrome::IsInstantExtendedAPIEnabled() &&
340       chrome::ShouldPrefetchSearchResults()) {
341     InstantSuggestion prefetch_suggestion;
342     // If the default match should be prefetched, do that.
343     if (SearchProvider::ShouldPrefetch(*default_match)) {
344       prefetch_suggestion.text = default_match->contents;
345       prefetch_suggestion.metadata =
346           SearchProvider::GetSuggestMetadata(*default_match);
347     }
348     // Send the prefetch suggestion unconditionally to the Instant search base
349     // page. If there is no suggestion to prefetch, we need to send a blank
350     // query to clear the prefetched results.
351     InstantSearchPrerenderer* prerenderer =
352         InstantSearchPrerenderer::GetForProfile(profile_);
353     if (prerenderer)
354       prerenderer->Prerender(prefetch_suggestion);
355   }
356   if (!inside_synchronous_start_)
357     NotifySuggestionsReceived(autocomplete_controller_->result());
358 }
359 
NotifySuggestionsReceived(const AutocompleteResult & autocomplete_result)360 void AutocompleteControllerAndroid::NotifySuggestionsReceived(
361     const AutocompleteResult& autocomplete_result) {
362   JNIEnv* env = AttachCurrentThread();
363   ScopedJavaLocalRef<jobject> java_bridge =
364       weak_java_autocomplete_controller_android_.get(env);
365   if (!java_bridge.obj())
366     return;
367 
368   ScopedJavaLocalRef<jobject> suggestion_list_obj =
369       Java_AutocompleteController_createOmniboxSuggestionList(
370           env, autocomplete_result.size());
371   for (size_t i = 0; i < autocomplete_result.size(); ++i) {
372     ScopedJavaLocalRef<jobject> j_omnibox_suggestion =
373         BuildOmniboxSuggestion(env, autocomplete_result.match_at(i));
374     Java_AutocompleteController_addOmniboxSuggestionToList(
375         env, suggestion_list_obj.obj(), j_omnibox_suggestion.obj());
376   }
377 
378   // Get the inline-autocomplete text.
379   const AutocompleteResult::const_iterator default_match(
380       autocomplete_result.default_match());
381   base::string16 inline_autocomplete_text;
382   if (default_match != autocomplete_result.end()) {
383     inline_autocomplete_text = default_match->inline_autocompletion;
384   }
385   ScopedJavaLocalRef<jstring> inline_text =
386       ConvertUTF16ToJavaString(env, inline_autocomplete_text);
387   jlong j_autocomplete_result =
388       reinterpret_cast<intptr_t>(&(autocomplete_result));
389   Java_AutocompleteController_onSuggestionsReceived(env,
390                                                     java_bridge.obj(),
391                                                     suggestion_list_obj.obj(),
392                                                     inline_text.obj(),
393                                                     j_autocomplete_result);
394 }
395 
396 OmniboxEventProto::PageClassification
ClassifyPage(const GURL & gurl,bool is_query_in_omnibox,bool focused_from_fakebox) const397 AutocompleteControllerAndroid::ClassifyPage(const GURL& gurl,
398                                             bool is_query_in_omnibox,
399                                             bool focused_from_fakebox) const {
400   if (!gurl.is_valid())
401     return OmniboxEventProto::INVALID_SPEC;
402 
403   const std::string& url = gurl.spec();
404 
405   if (gurl.SchemeIs(content::kChromeUIScheme) &&
406       gurl.host() == chrome::kChromeUINewTabHost) {
407     return OmniboxEventProto::NTP;
408   }
409 
410   if (url == chrome::kChromeUINativeNewTabURL) {
411     return focused_from_fakebox ?
412         OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS :
413         OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS;
414   }
415 
416   if (url == url::kAboutBlankURL)
417     return OmniboxEventProto::BLANK;
418 
419   if (url == profile_->GetPrefs()->GetString(prefs::kHomePage))
420     return OmniboxEventProto::HOME_PAGE;
421 
422   if (is_query_in_omnibox)
423     return OmniboxEventProto::SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT;
424 
425   bool is_search_url = TemplateURLServiceFactory::GetForProfile(profile_)->
426       IsSearchResultsPageFromDefaultSearchProvider(gurl);
427   if (is_search_url)
428     return OmniboxEventProto::SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT;
429 
430   return OmniboxEventProto::OTHER;
431 }
432 
433 ScopedJavaLocalRef<jobject>
BuildOmniboxSuggestion(JNIEnv * env,const AutocompleteMatch & match)434 AutocompleteControllerAndroid::BuildOmniboxSuggestion(
435     JNIEnv* env,
436     const AutocompleteMatch& match) {
437   ScopedJavaLocalRef<jstring> contents =
438       ConvertUTF16ToJavaString(env, match.contents);
439   ScopedJavaLocalRef<jstring> description =
440       ConvertUTF16ToJavaString(env, match.description);
441   ScopedJavaLocalRef<jstring> answer_contents =
442       ConvertUTF16ToJavaString(env, match.answer_contents);
443   ScopedJavaLocalRef<jstring> answer_type =
444       ConvertUTF16ToJavaString(env, match.answer_type);
445   ScopedJavaLocalRef<jstring> fill_into_edit =
446       ConvertUTF16ToJavaString(env, match.fill_into_edit);
447   ScopedJavaLocalRef<jstring> destination_url =
448       ConvertUTF8ToJavaString(env, match.destination_url.spec());
449   // Note that we are also removing 'www' host from formatted url.
450   ScopedJavaLocalRef<jstring> formatted_url = ConvertUTF16ToJavaString(env,
451       FormatURLUsingAcceptLanguages(match.stripped_destination_url));
452   BookmarkModel* bookmark_model = BookmarkModelFactory::GetForProfile(profile_);
453   return Java_AutocompleteController_buildOmniboxSuggestion(
454       env,
455       match.type,
456       match.relevance,
457       match.transition,
458       contents.obj(),
459       description.obj(),
460       answer_contents.obj(),
461       answer_type.obj(),
462       fill_into_edit.obj(),
463       destination_url.obj(),
464       formatted_url.obj(),
465       bookmark_model && bookmark_model->IsBookmarked(match.destination_url),
466       match.SupportsDeletion());
467 }
468 
FormatURLUsingAcceptLanguages(GURL url)469 base::string16 AutocompleteControllerAndroid::FormatURLUsingAcceptLanguages(
470     GURL url) {
471   if (profile_ == NULL)
472     return base::string16();
473 
474   std::string languages(
475       profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
476 
477   return net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
478       net::UnescapeRule::SPACES, NULL, NULL, NULL);
479 }
480 
481 ScopedJavaLocalRef<jobject>
GetTopSynchronousResult(JNIEnv * env,jobject obj,jstring j_text,bool prevent_inline_autocomplete)482 AutocompleteControllerAndroid::GetTopSynchronousResult(
483     JNIEnv* env,
484     jobject obj,
485     jstring j_text,
486     bool prevent_inline_autocomplete) {
487   if (!autocomplete_controller_)
488     return ScopedJavaLocalRef<jobject>();
489 
490   inside_synchronous_start_ = true;
491   Start(env,
492         obj,
493         j_text,
494         NULL,
495         NULL,
496         prevent_inline_autocomplete,
497         false,
498         false,
499         false);
500   inside_synchronous_start_ = false;
501   DCHECK(autocomplete_controller_->done());
502   const AutocompleteResult& result = autocomplete_controller_->result();
503   if (result.empty())
504     return ScopedJavaLocalRef<jobject>();
505 
506   return BuildOmniboxSuggestion(env, *result.begin());
507 }
508 
Init(JNIEnv * env,jobject obj,jobject jprofile)509 static jlong Init(JNIEnv* env, jobject obj, jobject jprofile) {
510   Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
511   if (!profile)
512     return 0;
513 
514   AutocompleteControllerAndroid* native_bridge =
515       AutocompleteControllerAndroid::Factory::GetForProfile(profile, env, obj);
516   return reinterpret_cast<intptr_t>(native_bridge);
517 }
518 
QualifyPartialURLQuery(JNIEnv * env,jclass clazz,jstring jquery)519 static jstring QualifyPartialURLQuery(
520     JNIEnv* env, jclass clazz, jstring jquery) {
521   Profile* profile = ProfileManager::GetActiveUserProfile();
522   if (!profile)
523     return NULL;
524   AutocompleteMatch match;
525   base::string16 query_string(ConvertJavaStringToUTF16(env, jquery));
526   AutocompleteClassifierFactory::GetForProfile(profile)->Classify(
527       query_string,
528       false,
529       false,
530       OmniboxEventProto::INVALID_SPEC,
531       &match,
532       NULL);
533   if (!match.destination_url.is_valid())
534     return NULL;
535 
536   // Only return a URL if the match is a URL type.
537   if (match.type != AutocompleteMatchType::URL_WHAT_YOU_TYPED &&
538       match.type != AutocompleteMatchType::HISTORY_URL &&
539       match.type != AutocompleteMatchType::NAVSUGGEST)
540     return NULL;
541 
542   // As we are returning to Java, it is fine to call Release().
543   return ConvertUTF8ToJavaString(env, match.destination_url.spec()).Release();
544 }
545 
PrefetchZeroSuggestResults(JNIEnv * env,jclass clazz)546 static void PrefetchZeroSuggestResults(JNIEnv* env, jclass clazz) {
547   Profile* profile = ProfileManager::GetActiveUserProfile();
548   if (!profile)
549     return;
550 
551   if (!OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial())
552     return;
553 
554   // ZeroSuggestPrefetcher deletes itself after it's done prefetching.
555   new ZeroSuggestPrefetcher(profile);
556 }
557 
558 // Register native methods
RegisterAutocompleteControllerAndroid(JNIEnv * env)559 bool RegisterAutocompleteControllerAndroid(JNIEnv* env) {
560   return RegisterNativesImpl(env);
561 }
562