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 |