1 // Copyright (c) 2012 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 "content/browser/android/web_contents_observer_android.h" 6 7 #include <string> 8 9 #include <jni.h> 10 11 #include "base/android/jni_android.h" 12 #include "base/android/jni_string.h" 13 #include "base/android/scoped_java_ref.h" 14 #include "content/browser/renderer_host/render_widget_host_impl.h" 15 #include "content/browser/web_contents/web_contents_impl.h" 16 #include "content/public/browser/navigation_details.h" 17 #include "content/public/browser/navigation_entry.h" 18 #include "jni/WebContentsObserverAndroid_jni.h" 19 20 using base::android::AttachCurrentThread; 21 using base::android::ScopedJavaLocalRef; 22 using base::android::ConvertUTF8ToJavaString; 23 using base::android::ConvertUTF16ToJavaString; 24 25 namespace content { 26 27 WebContentsObserverAndroid::WebContentsObserverAndroid( 28 JNIEnv* env, 29 jobject obj, 30 WebContents* web_contents) 31 : WebContentsObserver(web_contents), 32 weak_java_observer_(env, obj){ 33 } 34 35 WebContentsObserverAndroid::~WebContentsObserverAndroid() { 36 } 37 38 jlong Init(JNIEnv* env, jobject obj, jobject java_web_contents) { 39 content::WebContents* web_contents = 40 content::WebContents::FromJavaWebContents(java_web_contents); 41 CHECK(web_contents); 42 43 WebContentsObserverAndroid* native_observer = new WebContentsObserverAndroid( 44 env, obj, web_contents); 45 return reinterpret_cast<intptr_t>(native_observer); 46 } 47 48 void WebContentsObserverAndroid::Destroy(JNIEnv* env, jobject obj) { 49 delete this; 50 } 51 52 void WebContentsObserverAndroid::WebContentsDestroyed() { 53 JNIEnv* env = AttachCurrentThread(); 54 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 55 if (obj.is_null()) { 56 delete this; 57 } else { 58 // The java side will destroy |this| 59 Java_WebContentsObserverAndroid_detachFromWebContents(env, obj.obj()); 60 } 61 } 62 63 void WebContentsObserverAndroid::RenderProcessGone( 64 base::TerminationStatus termination_status) { 65 JNIEnv* env = AttachCurrentThread(); 66 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 67 if (obj.is_null()) 68 return; 69 jboolean was_oom_protected = 70 termination_status == base::TERMINATION_STATUS_OOM_PROTECTED; 71 Java_WebContentsObserverAndroid_renderProcessGone( 72 env, obj.obj(), was_oom_protected); 73 } 74 75 void WebContentsObserverAndroid::DidStartLoading( 76 RenderViewHost* render_view_host) { 77 JNIEnv* env = AttachCurrentThread(); 78 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 79 if (obj.is_null()) 80 return; 81 ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString( 82 env, web_contents()->GetVisibleURL().spec())); 83 Java_WebContentsObserverAndroid_didStartLoading( 84 env, obj.obj(), jstring_url.obj()); 85 } 86 87 void WebContentsObserverAndroid::DidStopLoading( 88 RenderViewHost* render_view_host) { 89 JNIEnv* env = AttachCurrentThread(); 90 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 91 if (obj.is_null()) 92 return; 93 ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString( 94 env, web_contents()->GetLastCommittedURL().spec())); 95 Java_WebContentsObserverAndroid_didStopLoading( 96 env, obj.obj(), jstring_url.obj()); 97 } 98 99 void WebContentsObserverAndroid::DidFailProvisionalLoad( 100 int64 frame_id, 101 const base::string16& frame_unique_name, 102 bool is_main_frame, 103 const GURL& validated_url, 104 int error_code, 105 const base::string16& error_description, 106 RenderViewHost* render_view_host) { 107 DidFailLoadInternal( 108 true, is_main_frame, error_code, error_description, validated_url); 109 } 110 111 void WebContentsObserverAndroid::DidFailLoad( 112 int64 frame_id, 113 const GURL& validated_url, 114 bool is_main_frame, 115 int error_code, 116 const base::string16& error_description, 117 RenderViewHost* render_view_host) { 118 DidFailLoadInternal( 119 false, is_main_frame, error_code, error_description, validated_url); 120 } 121 122 void WebContentsObserverAndroid::DidNavigateMainFrame( 123 const LoadCommittedDetails& details, 124 const FrameNavigateParams& params) { 125 JNIEnv* env = AttachCurrentThread(); 126 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 127 if (obj.is_null()) 128 return; 129 ScopedJavaLocalRef<jstring> jstring_url( 130 ConvertUTF8ToJavaString(env, params.url.spec())); 131 ScopedJavaLocalRef<jstring> jstring_base_url( 132 ConvertUTF8ToJavaString(env, params.base_url.spec())); 133 134 // See http://crbug.com/251330 for why it's determined this way. 135 url::Replacements<char> replacements; 136 replacements.ClearRef(); 137 bool urls_same_ignoring_fragment = 138 params.url.ReplaceComponents(replacements) == 139 details.previous_url.ReplaceComponents(replacements); 140 141 // is_fragment_navigation is indicative of the intent of this variable. 142 // However, there isn't sufficient information here to determine whether this 143 // is actually a fragment navigation, or a history API navigation to a URL 144 // that would also be valid for a fragment navigation. 145 bool is_fragment_navigation = urls_same_ignoring_fragment && 146 (details.type == NAVIGATION_TYPE_IN_PAGE || details.is_in_page); 147 Java_WebContentsObserverAndroid_didNavigateMainFrame( 148 env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), 149 details.is_navigation_to_different_page(), is_fragment_navigation); 150 } 151 152 void WebContentsObserverAndroid::DidNavigateAnyFrame( 153 const LoadCommittedDetails& details, 154 const FrameNavigateParams& params) { 155 JNIEnv* env = AttachCurrentThread(); 156 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 157 if (obj.is_null()) 158 return; 159 ScopedJavaLocalRef<jstring> jstring_url( 160 ConvertUTF8ToJavaString(env, params.url.spec())); 161 ScopedJavaLocalRef<jstring> jstring_base_url( 162 ConvertUTF8ToJavaString(env, params.base_url.spec())); 163 jboolean jboolean_is_reload = 164 PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_RELOAD); 165 166 Java_WebContentsObserverAndroid_didNavigateAnyFrame( 167 env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), 168 jboolean_is_reload); 169 } 170 171 void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame( 172 int64 frame_id, 173 int64 parent_frame_id, 174 bool is_main_frame, 175 const GURL& validated_url, 176 bool is_error_page, 177 bool is_iframe_srcdoc, 178 RenderViewHost* render_view_host) { 179 JNIEnv* env = AttachCurrentThread(); 180 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 181 if (obj.is_null()) 182 return; 183 ScopedJavaLocalRef<jstring> jstring_url( 184 ConvertUTF8ToJavaString(env, validated_url.spec())); 185 Java_WebContentsObserverAndroid_didStartProvisionalLoadForFrame( 186 env, obj.obj(), frame_id, parent_frame_id, is_main_frame, 187 jstring_url.obj(), is_error_page, is_iframe_srcdoc); 188 } 189 190 void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame( 191 int64 frame_id, 192 const base::string16& frame_unique_name, 193 bool is_main_frame, 194 const GURL& url, 195 PageTransition transition_type, 196 RenderViewHost* render_view_host) { 197 JNIEnv* env = AttachCurrentThread(); 198 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 199 if (obj.is_null()) 200 return; 201 ScopedJavaLocalRef<jstring> jstring_url( 202 ConvertUTF8ToJavaString(env, url.spec())); 203 Java_WebContentsObserverAndroid_didCommitProvisionalLoadForFrame( 204 env, obj.obj(), frame_id, is_main_frame, jstring_url.obj(), 205 transition_type); 206 } 207 208 void WebContentsObserverAndroid::DidFinishLoad( 209 int64 frame_id, 210 const GURL& validated_url, 211 bool is_main_frame, 212 RenderViewHost* render_view_host) { 213 JNIEnv* env = AttachCurrentThread(); 214 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 215 if (obj.is_null()) 216 return; 217 218 std::string url_string = validated_url.spec(); 219 NavigationEntry* entry = 220 web_contents()->GetController().GetLastCommittedEntry(); 221 // Note that GetBaseURLForDataURL is only used by the Android WebView. 222 if (entry && !entry->GetBaseURLForDataURL().is_empty()) 223 url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec(); 224 225 ScopedJavaLocalRef<jstring> jstring_url( 226 ConvertUTF8ToJavaString(env, url_string)); 227 Java_WebContentsObserverAndroid_didFinishLoad( 228 env, obj.obj(), frame_id, jstring_url.obj(), is_main_frame); 229 } 230 231 void WebContentsObserverAndroid::DocumentLoadedInFrame( 232 int64 frame_id, 233 RenderViewHost* render_view_host) { 234 JNIEnv* env = AttachCurrentThread(); 235 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 236 if (obj.is_null()) 237 return; 238 Java_WebContentsObserverAndroid_documentLoadedInFrame( 239 env, obj.obj(), frame_id); 240 } 241 242 void WebContentsObserverAndroid::NavigationEntryCommitted( 243 const LoadCommittedDetails& load_details) { 244 JNIEnv* env = AttachCurrentThread(); 245 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 246 if (obj.is_null()) 247 return; 248 Java_WebContentsObserverAndroid_navigationEntryCommitted(env, obj.obj()); 249 } 250 251 void WebContentsObserverAndroid::DidAttachInterstitialPage() { 252 JNIEnv* env = AttachCurrentThread(); 253 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 254 if (obj.is_null()) 255 return; 256 Java_WebContentsObserverAndroid_didAttachInterstitialPage(env, obj.obj()); 257 } 258 259 void WebContentsObserverAndroid::DidDetachInterstitialPage() { 260 JNIEnv* env = AttachCurrentThread(); 261 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 262 if (obj.is_null()) 263 return; 264 Java_WebContentsObserverAndroid_didDetachInterstitialPage(env, obj.obj()); 265 } 266 267 void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) { 268 JNIEnv* env = AttachCurrentThread(); 269 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 270 if (obj.is_null()) 271 return; 272 Java_WebContentsObserverAndroid_didChangeThemeColor(env, obj.obj(), color); 273 } 274 275 void WebContentsObserverAndroid::DidFailLoadInternal( 276 bool is_provisional_load, 277 bool is_main_frame, 278 int error_code, 279 const base::string16& description, 280 const GURL& url) { 281 JNIEnv* env = AttachCurrentThread(); 282 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 283 if (obj.is_null()) 284 return; 285 ScopedJavaLocalRef<jstring> jstring_error_description( 286 ConvertUTF16ToJavaString(env, description)); 287 ScopedJavaLocalRef<jstring> jstring_url( 288 ConvertUTF8ToJavaString(env, url.spec())); 289 290 Java_WebContentsObserverAndroid_didFailLoad( 291 env, obj.obj(), 292 is_provisional_load, 293 is_main_frame, 294 error_code, 295 jstring_error_description.obj(), jstring_url.obj()); 296 } 297 298 void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() { 299 JNIEnv* env = AttachCurrentThread(); 300 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); 301 if (obj.is_null()) 302 return; 303 Java_WebContentsObserverAndroid_didFirstVisuallyNonEmptyPaint( 304 env, obj.obj()); 305 } 306 307 bool RegisterWebContentsObserverAndroid(JNIEnv* env) { 308 return RegisterNativesImpl(env); 309 } 310 } // namespace content 311