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