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::RenderProcessGone(
67 base::TerminationStatus termination_status
) {
68 JNIEnv
* env
= AttachCurrentThread();
69 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
72 jboolean was_oom_protected
=
73 termination_status
== base::TERMINATION_STATUS_OOM_PROTECTED
;
74 Java_WebContentsObserver_renderProcessGone(
75 env
, obj
.obj(), was_oom_protected
);
78 void WebContentsObserverAndroid::DidStartLoading(
79 RenderViewHost
* render_view_host
) {
80 JNIEnv
* env
= AttachCurrentThread();
81 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
84 ScopedJavaLocalRef
<jstring
> jstring_url(ConvertUTF8ToJavaString(
85 env
, web_contents()->GetVisibleURL().spec()));
86 Java_WebContentsObserver_didStartLoading(
87 env
, obj
.obj(), jstring_url
.obj());
90 void WebContentsObserverAndroid::DidStopLoading(
91 RenderViewHost
* render_view_host
) {
92 JNIEnv
* env
= AttachCurrentThread();
93 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
96 ScopedJavaLocalRef
<jstring
> jstring_url(ConvertUTF8ToJavaString(
97 env
, web_contents()->GetLastCommittedURL().spec()));
98 Java_WebContentsObserver_didStopLoading(
99 env
, obj
.obj(), jstring_url
.obj());
102 void WebContentsObserverAndroid::DidFailProvisionalLoad(
103 RenderFrameHost
* render_frame_host
,
104 const GURL
& validated_url
,
106 const base::string16
& error_description
) {
107 DidFailLoadInternal(true,
108 !render_frame_host
->GetParent(),
114 void WebContentsObserverAndroid::DidFailLoad(
115 RenderFrameHost
* render_frame_host
,
116 const GURL
& validated_url
,
118 const base::string16
& error_description
) {
119 DidFailLoadInternal(false,
120 !render_frame_host
->GetParent(),
126 void WebContentsObserverAndroid::DidNavigateMainFrame(
127 const LoadCommittedDetails
& details
,
128 const FrameNavigateParams
& params
) {
129 JNIEnv
* env
= AttachCurrentThread();
130 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
133 ScopedJavaLocalRef
<jstring
> jstring_url(
134 ConvertUTF8ToJavaString(env
, params
.url
.spec()));
135 ScopedJavaLocalRef
<jstring
> jstring_base_url(
136 ConvertUTF8ToJavaString(env
, params
.base_url
.spec()));
138 // See http://crbug.com/251330 for why it's determined this way.
139 url::Replacements
<char> replacements
;
140 replacements
.ClearRef();
141 bool urls_same_ignoring_fragment
=
142 params
.url
.ReplaceComponents(replacements
) ==
143 details
.previous_url
.ReplaceComponents(replacements
);
145 // is_fragment_navigation is indicative of the intent of this variable.
146 // However, there isn't sufficient information here to determine whether this
147 // is actually a fragment navigation, or a history API navigation to a URL
148 // that would also be valid for a fragment navigation.
149 bool is_fragment_navigation
= urls_same_ignoring_fragment
&&
150 (details
.type
== NAVIGATION_TYPE_IN_PAGE
|| details
.is_in_page
);
151 Java_WebContentsObserver_didNavigateMainFrame(
152 env
, obj
.obj(), jstring_url
.obj(), jstring_base_url
.obj(),
153 details
.is_navigation_to_different_page(), is_fragment_navigation
,
154 details
.http_status_code
);
157 void WebContentsObserverAndroid::DidNavigateAnyFrame(
158 RenderFrameHost
* render_frame_host
,
159 const LoadCommittedDetails
& details
,
160 const FrameNavigateParams
& params
) {
161 JNIEnv
* env
= AttachCurrentThread();
162 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
165 ScopedJavaLocalRef
<jstring
> jstring_url(
166 ConvertUTF8ToJavaString(env
, params
.url
.spec()));
167 ScopedJavaLocalRef
<jstring
> jstring_base_url(
168 ConvertUTF8ToJavaString(env
, params
.base_url
.spec()));
169 jboolean jboolean_is_reload
= ui::PageTransitionCoreTypeIs(
170 params
.transition
, ui::PAGE_TRANSITION_RELOAD
);
172 Java_WebContentsObserver_didNavigateAnyFrame(
173 env
, obj
.obj(), jstring_url
.obj(), jstring_base_url
.obj(),
177 void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
178 RenderFrameHost
* render_frame_host
,
179 const GURL
& validated_url
,
181 bool is_iframe_srcdoc
) {
182 JNIEnv
* env
= AttachCurrentThread();
183 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
186 ScopedJavaLocalRef
<jstring
> jstring_url(
187 ConvertUTF8ToJavaString(env
, validated_url
.spec()));
188 // TODO(dcheng): Does Java really need the parent frame ID? It doesn't appear
189 // to be used at all, and it just adds complexity here.
190 Java_WebContentsObserver_didStartProvisionalLoadForFrame(
193 render_frame_host
->GetRoutingID(),
194 render_frame_host
->GetParent()
195 ? render_frame_host
->GetParent()->GetRoutingID()
197 !render_frame_host
->GetParent(),
203 void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame(
204 RenderFrameHost
* render_frame_host
,
206 ui::PageTransition transition_type
) {
207 JNIEnv
* env
= AttachCurrentThread();
208 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
211 ScopedJavaLocalRef
<jstring
> jstring_url(
212 ConvertUTF8ToJavaString(env
, url
.spec()));
213 Java_WebContentsObserver_didCommitProvisionalLoadForFrame(
216 render_frame_host
->GetRoutingID(),
217 !render_frame_host
->GetParent(),
222 void WebContentsObserverAndroid::DidFinishLoad(
223 RenderFrameHost
* render_frame_host
,
224 const GURL
& validated_url
) {
225 JNIEnv
* env
= AttachCurrentThread();
226 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
230 std::string url_string
= validated_url
.spec();
231 NavigationEntry
* entry
=
232 web_contents()->GetController().GetLastCommittedEntry();
233 // Note that GetBaseURLForDataURL is only used by the Android WebView.
234 if (entry
&& !entry
->GetBaseURLForDataURL().is_empty())
235 url_string
= entry
->GetBaseURLForDataURL().possibly_invalid_spec();
237 ScopedJavaLocalRef
<jstring
> jstring_url(
238 ConvertUTF8ToJavaString(env
, url_string
));
239 Java_WebContentsObserver_didFinishLoad(
242 render_frame_host
->GetRoutingID(),
244 !render_frame_host
->GetParent());
247 void WebContentsObserverAndroid::DocumentLoadedInFrame(
248 RenderFrameHost
* render_frame_host
) {
249 JNIEnv
* env
= AttachCurrentThread();
250 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
253 Java_WebContentsObserver_documentLoadedInFrame(
254 env
, obj
.obj(), render_frame_host
->GetRoutingID());
257 void WebContentsObserverAndroid::NavigationEntryCommitted(
258 const LoadCommittedDetails
& load_details
) {
259 JNIEnv
* env
= AttachCurrentThread();
260 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
263 Java_WebContentsObserver_navigationEntryCommitted(env
, obj
.obj());
266 void WebContentsObserverAndroid::DidAttachInterstitialPage() {
267 JNIEnv
* env
= AttachCurrentThread();
268 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
271 Java_WebContentsObserver_didAttachInterstitialPage(env
, obj
.obj());
274 void WebContentsObserverAndroid::DidDetachInterstitialPage() {
275 JNIEnv
* env
= AttachCurrentThread();
276 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
279 Java_WebContentsObserver_didDetachInterstitialPage(env
, obj
.obj());
282 void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color
) {
283 JNIEnv
* env
= AttachCurrentThread();
284 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
287 Java_WebContentsObserver_didChangeThemeColor(env
, obj
.obj(), color
);
290 void WebContentsObserverAndroid::DidFailLoadInternal(
291 bool is_provisional_load
,
294 const base::string16
& description
,
296 JNIEnv
* env
= AttachCurrentThread();
297 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
300 ScopedJavaLocalRef
<jstring
> jstring_error_description(
301 ConvertUTF16ToJavaString(env
, description
));
302 ScopedJavaLocalRef
<jstring
> jstring_url(
303 ConvertUTF8ToJavaString(env
, url
.spec()));
305 Java_WebContentsObserver_didFailLoad(
310 jstring_error_description
.obj(), jstring_url
.obj());
313 void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() {
314 JNIEnv
* env
= AttachCurrentThread();
315 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
318 Java_WebContentsObserver_didFirstVisuallyNonEmptyPaint(
322 bool RegisterWebContentsObserverAndroid(JNIEnv
* env
) {
323 return RegisterNativesImpl(env
);
325 } // namespace content