| OLD | NEW |
| (Empty) |
| 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/WebContentsObserver_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 // TODO(dcheng): File a bug. This class incorrectly passes just a frame ID, | |
| 28 // which is not sufficient to identify a frame (since frame IDs are scoped per | |
| 29 // render process, and so may collide). | |
| 30 WebContentsObserverAndroid::WebContentsObserverAndroid( | |
| 31 JNIEnv* env, | |
| 32 jobject obj, | |
| 33 WebContents* web_contents) | |
| 34 : WebContentsObserver(web_contents), | |
| 35 weak_java_observer_(env, obj){ | |
| 36 } | |
| 37 | |
| 38 WebContentsObserverAndroid::~WebContentsObserverAndroid() { | |
| 39 } | |
| 40 | |
| 41 jlong Init(JNIEnv* env, jobject obj, jobject java_web_contents) { | |
| 42 WebContents* web_contents = | |
| 43 WebContents::FromJavaWebContents(java_web_contents); | |
| 44 CHECK(web_contents); | |
| 45 | |
| 46 WebContentsObserverAndroid* native_observer = new WebContentsObserverAndroid( | |
| 47 env, obj, web_contents); | |
| 48 return reinterpret_cast<intptr_t>(native_observer); | |
| 49 } | |
| 50 | |
| 51 void WebContentsObserverAndroid::Destroy(JNIEnv* env, jobject obj) { | |
| 52 delete this; | |
| 53 } | |
| 54 | |
| 55 void WebContentsObserverAndroid::WebContentsDestroyed() { | |
| 56 JNIEnv* env = AttachCurrentThread(); | |
| 57 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 58 if (obj.is_null()) { | |
| 59 delete this; | |
| 60 } else { | |
| 61 // The java side will destroy |this| | |
| 62 Java_WebContentsObserver_detachFromWebContents(env, obj.obj()); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 void WebContentsObserverAndroid::RenderViewReady() { | |
| 67 JNIEnv* env = AttachCurrentThread(); | |
| 68 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 69 if (obj.is_null()) | |
| 70 return; | |
| 71 Java_WebContentsObserver_renderViewReady(env, obj.obj()); | |
| 72 } | |
| 73 | |
| 74 void WebContentsObserverAndroid::RenderProcessGone( | |
| 75 base::TerminationStatus termination_status) { | |
| 76 JNIEnv* env = AttachCurrentThread(); | |
| 77 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 78 if (obj.is_null()) | |
| 79 return; | |
| 80 jboolean was_oom_protected = | |
| 81 termination_status == base::TERMINATION_STATUS_OOM_PROTECTED; | |
| 82 Java_WebContentsObserver_renderProcessGone( | |
| 83 env, obj.obj(), was_oom_protected); | |
| 84 } | |
| 85 | |
| 86 void WebContentsObserverAndroid::DidStartLoading( | |
| 87 RenderViewHost* render_view_host) { | |
| 88 JNIEnv* env = AttachCurrentThread(); | |
| 89 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 90 if (obj.is_null()) | |
| 91 return; | |
| 92 ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString( | |
| 93 env, web_contents()->GetVisibleURL().spec())); | |
| 94 Java_WebContentsObserver_didStartLoading( | |
| 95 env, obj.obj(), jstring_url.obj()); | |
| 96 } | |
| 97 | |
| 98 void WebContentsObserverAndroid::DidStopLoading( | |
| 99 RenderViewHost* render_view_host) { | |
| 100 JNIEnv* env = AttachCurrentThread(); | |
| 101 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 102 if (obj.is_null()) | |
| 103 return; | |
| 104 ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString( | |
| 105 env, web_contents()->GetLastCommittedURL().spec())); | |
| 106 Java_WebContentsObserver_didStopLoading( | |
| 107 env, obj.obj(), jstring_url.obj()); | |
| 108 } | |
| 109 | |
| 110 void WebContentsObserverAndroid::DidFailProvisionalLoad( | |
| 111 RenderFrameHost* render_frame_host, | |
| 112 const GURL& validated_url, | |
| 113 int error_code, | |
| 114 const base::string16& error_description) { | |
| 115 DidFailLoadInternal(true, | |
| 116 !render_frame_host->GetParent(), | |
| 117 error_code, | |
| 118 error_description, | |
| 119 validated_url); | |
| 120 } | |
| 121 | |
| 122 void WebContentsObserverAndroid::DidFailLoad( | |
| 123 RenderFrameHost* render_frame_host, | |
| 124 const GURL& validated_url, | |
| 125 int error_code, | |
| 126 const base::string16& error_description) { | |
| 127 DidFailLoadInternal(false, | |
| 128 !render_frame_host->GetParent(), | |
| 129 error_code, | |
| 130 error_description, | |
| 131 validated_url); | |
| 132 } | |
| 133 | |
| 134 void WebContentsObserverAndroid::DidNavigateMainFrame( | |
| 135 const LoadCommittedDetails& details, | |
| 136 const FrameNavigateParams& params) { | |
| 137 JNIEnv* env = AttachCurrentThread(); | |
| 138 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 139 if (obj.is_null()) | |
| 140 return; | |
| 141 ScopedJavaLocalRef<jstring> jstring_url( | |
| 142 ConvertUTF8ToJavaString(env, params.url.spec())); | |
| 143 ScopedJavaLocalRef<jstring> jstring_base_url( | |
| 144 ConvertUTF8ToJavaString(env, params.base_url.spec())); | |
| 145 | |
| 146 // See http://crbug.com/251330 for why it's determined this way. | |
| 147 url::Replacements<char> replacements; | |
| 148 replacements.ClearRef(); | |
| 149 bool urls_same_ignoring_fragment = | |
| 150 params.url.ReplaceComponents(replacements) == | |
| 151 details.previous_url.ReplaceComponents(replacements); | |
| 152 | |
| 153 // is_fragment_navigation is indicative of the intent of this variable. | |
| 154 // However, there isn't sufficient information here to determine whether this | |
| 155 // is actually a fragment navigation, or a history API navigation to a URL | |
| 156 // that would also be valid for a fragment navigation. | |
| 157 bool is_fragment_navigation = urls_same_ignoring_fragment && | |
| 158 (details.type == NAVIGATION_TYPE_IN_PAGE || details.is_in_page); | |
| 159 Java_WebContentsObserver_didNavigateMainFrame( | |
| 160 env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), | |
| 161 details.is_navigation_to_different_page(), is_fragment_navigation, | |
| 162 details.http_status_code); | |
| 163 } | |
| 164 | |
| 165 void WebContentsObserverAndroid::DidNavigateAnyFrame( | |
| 166 RenderFrameHost* render_frame_host, | |
| 167 const LoadCommittedDetails& details, | |
| 168 const FrameNavigateParams& params) { | |
| 169 JNIEnv* env = AttachCurrentThread(); | |
| 170 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 171 if (obj.is_null()) | |
| 172 return; | |
| 173 ScopedJavaLocalRef<jstring> jstring_url( | |
| 174 ConvertUTF8ToJavaString(env, params.url.spec())); | |
| 175 ScopedJavaLocalRef<jstring> jstring_base_url( | |
| 176 ConvertUTF8ToJavaString(env, params.base_url.spec())); | |
| 177 jboolean jboolean_is_reload = ui::PageTransitionCoreTypeIs( | |
| 178 params.transition, ui::PAGE_TRANSITION_RELOAD); | |
| 179 | |
| 180 Java_WebContentsObserver_didNavigateAnyFrame( | |
| 181 env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), | |
| 182 jboolean_is_reload); | |
| 183 } | |
| 184 | |
| 185 void WebContentsObserverAndroid::DocumentAvailableInMainFrame() { | |
| 186 JNIEnv* env = AttachCurrentThread(); | |
| 187 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 188 if (obj.is_null()) | |
| 189 return; | |
| 190 Java_WebContentsObserver_documentAvailableInMainFrame(env, obj.obj()); | |
| 191 } | |
| 192 | |
| 193 void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame( | |
| 194 RenderFrameHost* render_frame_host, | |
| 195 const GURL& validated_url, | |
| 196 bool is_error_page, | |
| 197 bool is_iframe_srcdoc) { | |
| 198 JNIEnv* env = AttachCurrentThread(); | |
| 199 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 200 if (obj.is_null()) | |
| 201 return; | |
| 202 ScopedJavaLocalRef<jstring> jstring_url( | |
| 203 ConvertUTF8ToJavaString(env, validated_url.spec())); | |
| 204 // TODO(dcheng): Does Java really need the parent frame ID? It doesn't appear | |
| 205 // to be used at all, and it just adds complexity here. | |
| 206 Java_WebContentsObserver_didStartProvisionalLoadForFrame( | |
| 207 env, | |
| 208 obj.obj(), | |
| 209 render_frame_host->GetRoutingID(), | |
| 210 render_frame_host->GetParent() | |
| 211 ? render_frame_host->GetParent()->GetRoutingID() | |
| 212 : -1, | |
| 213 !render_frame_host->GetParent(), | |
| 214 jstring_url.obj(), | |
| 215 is_error_page, | |
| 216 is_iframe_srcdoc); | |
| 217 } | |
| 218 | |
| 219 void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame( | |
| 220 RenderFrameHost* render_frame_host, | |
| 221 const GURL& url, | |
| 222 ui::PageTransition transition_type) { | |
| 223 JNIEnv* env = AttachCurrentThread(); | |
| 224 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 225 if (obj.is_null()) | |
| 226 return; | |
| 227 ScopedJavaLocalRef<jstring> jstring_url( | |
| 228 ConvertUTF8ToJavaString(env, url.spec())); | |
| 229 Java_WebContentsObserver_didCommitProvisionalLoadForFrame( | |
| 230 env, | |
| 231 obj.obj(), | |
| 232 render_frame_host->GetRoutingID(), | |
| 233 !render_frame_host->GetParent(), | |
| 234 jstring_url.obj(), | |
| 235 transition_type); | |
| 236 } | |
| 237 | |
| 238 void WebContentsObserverAndroid::DidFinishLoad( | |
| 239 RenderFrameHost* render_frame_host, | |
| 240 const GURL& validated_url) { | |
| 241 JNIEnv* env = AttachCurrentThread(); | |
| 242 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 243 if (obj.is_null()) | |
| 244 return; | |
| 245 | |
| 246 std::string url_string = validated_url.spec(); | |
| 247 NavigationEntry* entry = | |
| 248 web_contents()->GetController().GetLastCommittedEntry(); | |
| 249 // Note that GetBaseURLForDataURL is only used by the Android WebView. | |
| 250 if (entry && !entry->GetBaseURLForDataURL().is_empty()) | |
| 251 url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec(); | |
| 252 | |
| 253 ScopedJavaLocalRef<jstring> jstring_url( | |
| 254 ConvertUTF8ToJavaString(env, url_string)); | |
| 255 Java_WebContentsObserver_didFinishLoad( | |
| 256 env, | |
| 257 obj.obj(), | |
| 258 render_frame_host->GetRoutingID(), | |
| 259 jstring_url.obj(), | |
| 260 !render_frame_host->GetParent()); | |
| 261 } | |
| 262 | |
| 263 void WebContentsObserverAndroid::DocumentLoadedInFrame( | |
| 264 RenderFrameHost* render_frame_host) { | |
| 265 JNIEnv* env = AttachCurrentThread(); | |
| 266 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 267 if (obj.is_null()) | |
| 268 return; | |
| 269 Java_WebContentsObserver_documentLoadedInFrame( | |
| 270 env, obj.obj(), render_frame_host->GetRoutingID()); | |
| 271 } | |
| 272 | |
| 273 void WebContentsObserverAndroid::NavigationEntryCommitted( | |
| 274 const LoadCommittedDetails& load_details) { | |
| 275 JNIEnv* env = AttachCurrentThread(); | |
| 276 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 277 if (obj.is_null()) | |
| 278 return; | |
| 279 Java_WebContentsObserver_navigationEntryCommitted(env, obj.obj()); | |
| 280 } | |
| 281 | |
| 282 void WebContentsObserverAndroid::DidAttachInterstitialPage() { | |
| 283 JNIEnv* env = AttachCurrentThread(); | |
| 284 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 285 if (obj.is_null()) | |
| 286 return; | |
| 287 Java_WebContentsObserver_didAttachInterstitialPage(env, obj.obj()); | |
| 288 } | |
| 289 | |
| 290 void WebContentsObserverAndroid::DidDetachInterstitialPage() { | |
| 291 JNIEnv* env = AttachCurrentThread(); | |
| 292 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 293 if (obj.is_null()) | |
| 294 return; | |
| 295 Java_WebContentsObserver_didDetachInterstitialPage(env, obj.obj()); | |
| 296 } | |
| 297 | |
| 298 void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) { | |
| 299 JNIEnv* env = AttachCurrentThread(); | |
| 300 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 301 if (obj.is_null()) | |
| 302 return; | |
| 303 Java_WebContentsObserver_didChangeThemeColor(env, obj.obj(), color); | |
| 304 } | |
| 305 | |
| 306 void WebContentsObserverAndroid::DidFailLoadInternal( | |
| 307 bool is_provisional_load, | |
| 308 bool is_main_frame, | |
| 309 int error_code, | |
| 310 const base::string16& description, | |
| 311 const GURL& url) { | |
| 312 JNIEnv* env = AttachCurrentThread(); | |
| 313 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 314 if (obj.is_null()) | |
| 315 return; | |
| 316 ScopedJavaLocalRef<jstring> jstring_error_description( | |
| 317 ConvertUTF16ToJavaString(env, description)); | |
| 318 ScopedJavaLocalRef<jstring> jstring_url( | |
| 319 ConvertUTF8ToJavaString(env, url.spec())); | |
| 320 | |
| 321 Java_WebContentsObserver_didFailLoad( | |
| 322 env, obj.obj(), | |
| 323 is_provisional_load, | |
| 324 is_main_frame, | |
| 325 error_code, | |
| 326 jstring_error_description.obj(), jstring_url.obj()); | |
| 327 } | |
| 328 | |
| 329 void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() { | |
| 330 JNIEnv* env = AttachCurrentThread(); | |
| 331 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 332 if (obj.is_null()) | |
| 333 return; | |
| 334 Java_WebContentsObserver_didFirstVisuallyNonEmptyPaint( | |
| 335 env, obj.obj()); | |
| 336 } | |
| 337 | |
| 338 void WebContentsObserverAndroid::DidStartNavigationToPendingEntry( | |
| 339 const GURL& url, | |
| 340 NavigationController::ReloadType reload_type) { | |
| 341 JNIEnv* env = AttachCurrentThread(); | |
| 342 ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env)); | |
| 343 if (obj.is_null()) | |
| 344 return; | |
| 345 ScopedJavaLocalRef<jstring> jstring_url( | |
| 346 ConvertUTF8ToJavaString(env, url.spec())); | |
| 347 | |
| 348 Java_WebContentsObserver_didStartNavigationToPendingEntry(env, obj.obj(), | |
| 349 jstring_url.obj()); | |
| 350 } | |
| 351 | |
| 352 bool RegisterWebContentsObserverAndroid(JNIEnv* env) { | |
| 353 return RegisterNativesImpl(env); | |
| 354 } | |
| 355 } // namespace content | |
| OLD | NEW |