Home | History | Annotate | Download | only in omnibox
      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 
     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 
    104 ZeroSuggestPrefetcher::~ZeroSuggestPrefetcher() {
    105 }
    106 
    107 void ZeroSuggestPrefetcher::SelfDestruct() {
    108   delete this;
    109 }
    110 
    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 
    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 
    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 
    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 
    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 
    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 
    195 void AutocompleteControllerAndroid::ResetSession(JNIEnv* env, jobject obj) {
    196   if (autocomplete_controller_ != NULL)
    197     autocomplete_controller_->ResetSession();
    198 }
    199 
    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 
    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::
    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>
    267 AutocompleteControllerAndroid::GetTopSynchronousMatch(JNIEnv* env,
    268                                                       jobject obj,
    269                                                       jstring query) {
    270   return GetTopSynchronousResult(env, obj, query, false);
    271 }
    272 
    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*
    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*
    297 AutocompleteControllerAndroid::Factory::GetInstance() {
    298   return Singleton<AutocompleteControllerAndroid::Factory>::get();
    299 }
    300 
    301 content::BrowserContext*
    302 AutocompleteControllerAndroid::Factory::GetBrowserContextToUse(
    303     content::BrowserContext* context) const {
    304   return chrome::GetBrowserContextOwnInstanceInIncognito(context);
    305 }
    306 
    307 AutocompleteControllerAndroid::Factory::Factory()
    308     : BrowserContextKeyedServiceFactory(
    309           "AutocompleteControllerAndroid",
    310           BrowserContextDependencyManager::GetInstance()) {
    311   DependsOn(ShortcutsBackendFactory::GetInstance());
    312 }
    313 
    314 AutocompleteControllerAndroid::Factory::~Factory() {
    315 }
    316 
    317 KeyedService* AutocompleteControllerAndroid::Factory::BuildServiceInstanceFor(
    318     content::BrowserContext* profile) const {
    319   return new AutocompleteControllerAndroid(static_cast<Profile*>(profile));
    320 }
    321 
    322 AutocompleteControllerAndroid::~AutocompleteControllerAndroid() {
    323 }
    324 
    325 void AutocompleteControllerAndroid::InitJNI(JNIEnv* env, jobject obj) {
    326   weak_java_autocomplete_controller_android_ =
    327       JavaObjectWeakGlobalRef(env, obj);
    328 }
    329 
    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 
    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
    397 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>
    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 
    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>
    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 
    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 
    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 
    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
    559 bool RegisterAutocompleteControllerAndroid(JNIEnv* env) {
    560   return RegisterNativesImpl(env);
    561 }
    562