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.
5 #include "content/browser/android/web_contents_observer_android.h"
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"
20 using base::android::AttachCurrentThread
;
21 using base::android::ScopedJavaLocalRef
;
22 using base::android::ConvertUTF8ToJavaString
;
23 using base::android::ConvertUTF16ToJavaString
;
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(
33 WebContents
* web_contents
)
34 : WebContentsObserver(web_contents
),
35 weak_java_observer_(env
, obj
){
38 WebContentsObserverAndroid::~WebContentsObserverAndroid() {
41 jlong
Init(JNIEnv
* env
, jobject obj
, jobject java_web_contents
) {
42 WebContents
* web_contents
=
43 WebContents::FromJavaWebContents(java_web_contents
);
46 WebContentsObserverAndroid
* native_observer
= new WebContentsObserverAndroid(
47 env
, obj
, web_contents
);
48 return reinterpret_cast<intptr_t>(native_observer
);
51 void WebContentsObserverAndroid::Destroy(JNIEnv
* env
, jobject obj
) {
55 void WebContentsObserverAndroid::WebContentsDestroyed() {
56 JNIEnv
* env
= AttachCurrentThread();
57 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
61 // The java side will destroy |this|
62 Java_WebContentsObserver_detachFromWebContents(env
, obj
.obj());
66 void WebContentsObserverAndroid::RenderViewReady() {
67 JNIEnv
* env
= AttachCurrentThread();
68 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
71 Java_WebContentsObserver_renderViewReady(env
, obj
.obj());
74 void WebContentsObserverAndroid::RenderProcessGone(
75 base::TerminationStatus termination_status
) {
76 JNIEnv
* env
= AttachCurrentThread();
77 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
80 jboolean was_oom_protected
=
81 termination_status
== base::TERMINATION_STATUS_OOM_PROTECTED
;
82 Java_WebContentsObserver_renderProcessGone(
83 env
, obj
.obj(), was_oom_protected
);
86 void WebContentsObserverAndroid::DidStartLoading(
87 RenderViewHost
* render_view_host
) {
88 JNIEnv
* env
= AttachCurrentThread();
89 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
92 ScopedJavaLocalRef
<jstring
> jstring_url(ConvertUTF8ToJavaString(
93 env
, web_contents()->GetVisibleURL().spec()));
94 Java_WebContentsObserver_didStartLoading(
95 env
, obj
.obj(), jstring_url
.obj());
98 void WebContentsObserverAndroid::DidStopLoading(
99 RenderViewHost
* render_view_host
) {
100 JNIEnv
* env
= AttachCurrentThread();
101 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
104 ScopedJavaLocalRef
<jstring
> jstring_url(ConvertUTF8ToJavaString(
105 env
, web_contents()->GetLastCommittedURL().spec()));
106 Java_WebContentsObserver_didStopLoading(
107 env
, obj
.obj(), jstring_url
.obj());
110 void WebContentsObserverAndroid::DidFailProvisionalLoad(
111 RenderFrameHost
* render_frame_host
,
112 const GURL
& validated_url
,
114 const base::string16
& error_description
) {
115 DidFailLoadInternal(true,
116 !render_frame_host
->GetParent(),
122 void WebContentsObserverAndroid::DidFailLoad(
123 RenderFrameHost
* render_frame_host
,
124 const GURL
& validated_url
,
126 const base::string16
& error_description
) {
127 DidFailLoadInternal(false,
128 !render_frame_host
->GetParent(),
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
));
141 ScopedJavaLocalRef
<jstring
> jstring_url(
142 ConvertUTF8ToJavaString(env
, params
.url
.spec()));
143 ScopedJavaLocalRef
<jstring
> jstring_base_url(
144 ConvertUTF8ToJavaString(env
, params
.base_url
.spec()));
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
);
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
);
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
));
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
);
180 Java_WebContentsObserver_didNavigateAnyFrame(
181 env
, obj
.obj(), jstring_url
.obj(), jstring_base_url
.obj(),
185 void WebContentsObserverAndroid::DocumentAvailableInMainFrame() {
186 JNIEnv
* env
= AttachCurrentThread();
187 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
190 Java_WebContentsObserver_documentAvailableInMainFrame(env
, obj
.obj());
193 void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
194 RenderFrameHost
* render_frame_host
,
195 const GURL
& validated_url
,
197 bool is_iframe_srcdoc
) {
198 JNIEnv
* env
= AttachCurrentThread();
199 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
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(
209 render_frame_host
->GetRoutingID(),
210 render_frame_host
->GetParent()
211 ? render_frame_host
->GetParent()->GetRoutingID()
213 !render_frame_host
->GetParent(),
219 void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame(
220 RenderFrameHost
* render_frame_host
,
222 ui::PageTransition transition_type
) {
223 JNIEnv
* env
= AttachCurrentThread();
224 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
227 ScopedJavaLocalRef
<jstring
> jstring_url(
228 ConvertUTF8ToJavaString(env
, url
.spec()));
229 Java_WebContentsObserver_didCommitProvisionalLoadForFrame(
232 render_frame_host
->GetRoutingID(),
233 !render_frame_host
->GetParent(),
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
));
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();
253 ScopedJavaLocalRef
<jstring
> jstring_url(
254 ConvertUTF8ToJavaString(env
, url_string
));
255 Java_WebContentsObserver_didFinishLoad(
258 render_frame_host
->GetRoutingID(),
260 !render_frame_host
->GetParent());
263 void WebContentsObserverAndroid::DocumentLoadedInFrame(
264 RenderFrameHost
* render_frame_host
) {
265 JNIEnv
* env
= AttachCurrentThread();
266 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
269 Java_WebContentsObserver_documentLoadedInFrame(
270 env
, obj
.obj(), render_frame_host
->GetRoutingID());
273 void WebContentsObserverAndroid::NavigationEntryCommitted(
274 const LoadCommittedDetails
& load_details
) {
275 JNIEnv
* env
= AttachCurrentThread();
276 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
279 Java_WebContentsObserver_navigationEntryCommitted(env
, obj
.obj());
282 void WebContentsObserverAndroid::DidAttachInterstitialPage() {
283 JNIEnv
* env
= AttachCurrentThread();
284 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
287 Java_WebContentsObserver_didAttachInterstitialPage(env
, obj
.obj());
290 void WebContentsObserverAndroid::DidDetachInterstitialPage() {
291 JNIEnv
* env
= AttachCurrentThread();
292 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
295 Java_WebContentsObserver_didDetachInterstitialPage(env
, obj
.obj());
298 void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color
) {
299 JNIEnv
* env
= AttachCurrentThread();
300 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
303 Java_WebContentsObserver_didChangeThemeColor(env
, obj
.obj(), color
);
306 void WebContentsObserverAndroid::DidFailLoadInternal(
307 bool is_provisional_load
,
310 const base::string16
& description
,
312 JNIEnv
* env
= AttachCurrentThread();
313 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
316 ScopedJavaLocalRef
<jstring
> jstring_error_description(
317 ConvertUTF16ToJavaString(env
, description
));
318 ScopedJavaLocalRef
<jstring
> jstring_url(
319 ConvertUTF8ToJavaString(env
, url
.spec()));
321 Java_WebContentsObserver_didFailLoad(
326 jstring_error_description
.obj(), jstring_url
.obj());
329 void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() {
330 JNIEnv
* env
= AttachCurrentThread();
331 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
334 Java_WebContentsObserver_didFirstVisuallyNonEmptyPaint(
338 void WebContentsObserverAndroid::DidStartNavigationToPendingEntry(
340 NavigationController::ReloadType reload_type
) {
341 JNIEnv
* env
= AttachCurrentThread();
342 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
345 ScopedJavaLocalRef
<jstring
> jstring_url(
346 ConvertUTF8ToJavaString(env
, url
.spec()));
348 Java_WebContentsObserver_didStartNavigationToPendingEntry(env
, obj
.obj(),
352 bool RegisterWebContentsObserverAndroid(JNIEnv
* env
) {
353 return RegisterNativesImpl(env
);
355 } // namespace content