1 // Copyright 2013 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 "omnibox_prerender.h" 6 7 #include "base/android/jni_string.h" 8 #include "base/logging.h" 9 #include "chrome/browser/android/tab_android.h" 10 #include "chrome/browser/autocomplete/autocomplete_match.h" 11 #include "chrome/browser/autocomplete/autocomplete_result.h" 12 #include "chrome/browser/predictors/autocomplete_action_predictor.h" 13 #include "chrome/browser/predictors/autocomplete_action_predictor_factory.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile_android.h" 16 #include "chrome/browser/ui/search/instant_search_prerenderer.h" 17 #include "content/public/browser/web_contents.h" 18 #include "jni/OmniboxPrerender_jni.h" 19 #include "url/gurl.h" 20 21 using predictors::AutocompleteActionPredictor; 22 using predictors::AutocompleteActionPredictorFactory; 23 24 OmniboxPrerender::OmniboxPrerender(JNIEnv* env, jobject obj) 25 : weak_java_omnibox_(env, obj) { 26 } 27 28 OmniboxPrerender::~OmniboxPrerender() { 29 } 30 31 static jlong Init(JNIEnv* env, jobject obj) { 32 OmniboxPrerender* omnibox = new OmniboxPrerender(env, obj); 33 return reinterpret_cast<intptr_t>(omnibox); 34 } 35 36 bool RegisterOmniboxPrerender(JNIEnv* env) { 37 return RegisterNativesImpl(env); 38 } 39 40 void OmniboxPrerender::Clear(JNIEnv* env, 41 jobject obj, 42 jobject j_profile_android) { 43 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile_android); 44 DCHECK(profile); 45 if (!profile) 46 return; 47 AutocompleteActionPredictor* action_predictor = 48 AutocompleteActionPredictorFactory::GetForProfile(profile); 49 action_predictor->ClearTransitionalMatches(); 50 action_predictor->CancelPrerender(); 51 } 52 53 void OmniboxPrerender::InitializeForProfile( 54 JNIEnv* env, 55 jobject obj, 56 jobject j_profile_android) { 57 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile_android); 58 // Initialize the AutocompleteActionPredictor for this profile. 59 // It needs to register for notifications as part of its initialization. 60 AutocompleteActionPredictorFactory::GetForProfile(profile); 61 } 62 63 void OmniboxPrerender::PrerenderMaybe(JNIEnv* env, 64 jobject obj, 65 jstring j_url, 66 jstring j_current_url, 67 jlong jsource_match, 68 jobject j_profile_android, 69 jobject j_tab) { 70 AutocompleteResult* autocomplete_result = 71 reinterpret_cast<AutocompleteResult*>(jsource_match); 72 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile_android); 73 base::string16 url_string = 74 base::android::ConvertJavaStringToUTF16(env, j_url); 75 base::string16 current_url_string = 76 base::android::ConvertJavaStringToUTF16(env, j_current_url); 77 content::WebContents* web_contents = 78 TabAndroid::GetNativeTab(env, j_tab)->web_contents(); 79 // TODO(apiccion) Use a delegate for communicating with web_contents. 80 // This can happen in OmniboxTests since the results are generated 81 // in Java only. 82 if (!autocomplete_result) 83 return; 84 if (!profile) 85 return; 86 87 const AutocompleteResult::const_iterator default_match( 88 autocomplete_result->default_match()); 89 if (default_match == autocomplete_result->end()) 90 return; 91 92 AutocompleteActionPredictor::Action recommended_action = 93 AutocompleteActionPredictor::ACTION_NONE; 94 InstantSearchPrerenderer* prerenderer = 95 InstantSearchPrerenderer::GetForProfile(profile); 96 if (prerenderer && 97 prerenderer->IsAllowed(*default_match, web_contents)) { 98 recommended_action = AutocompleteActionPredictor::ACTION_PRERENDER; 99 } else { 100 AutocompleteActionPredictor* action_predictor = 101 AutocompleteActionPredictorFactory::GetForProfile(profile); 102 if (!action_predictor) 103 return; 104 105 if (action_predictor) { 106 action_predictor-> 107 RegisterTransitionalMatches(url_string, *autocomplete_result); 108 recommended_action = 109 action_predictor->RecommendAction(url_string, *default_match); 110 } 111 } 112 113 GURL current_url = GURL(current_url_string); 114 switch (recommended_action) { 115 case AutocompleteActionPredictor::ACTION_PRERENDER: 116 // Ask for prerendering if the destination URL is different than the 117 // current URL. 118 if (default_match->destination_url != current_url) { 119 DoPrerender( 120 *default_match, 121 profile, 122 web_contents); 123 } 124 break; 125 case AutocompleteActionPredictor::ACTION_PRECONNECT: 126 // TODO (apiccion) add preconnect logic 127 break; 128 case AutocompleteActionPredictor::ACTION_NONE: 129 break; 130 default: 131 NOTREACHED(); 132 break; 133 } 134 } 135 136 void OmniboxPrerender::DoPrerender(const AutocompleteMatch& match, 137 Profile* profile, 138 content::WebContents* web_contents) { 139 DCHECK(profile); 140 if (!profile) 141 return; 142 DCHECK(web_contents); 143 if (!web_contents) 144 return; 145 gfx::Rect container_bounds = web_contents->GetContainerBounds(); 146 InstantSearchPrerenderer* prerenderer = 147 InstantSearchPrerenderer::GetForProfile(profile); 148 if (prerenderer && prerenderer->IsAllowed(match, web_contents)) { 149 prerenderer->Init( 150 web_contents->GetController().GetSessionStorageNamespaceMap(), 151 container_bounds.size()); 152 return; 153 } 154 predictors::AutocompleteActionPredictorFactory::GetForProfile(profile)-> 155 StartPrerendering( 156 match.destination_url, 157 web_contents->GetController().GetSessionStorageNamespaceMap(), 158 container_bounds.size()); 159 } 160