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/WebContentsObserverAndroid_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_WebContentsObserverAndroid_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_WebContentsObserverAndroid_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_WebContentsObserverAndroid_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_WebContentsObserverAndroid_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_WebContentsObserverAndroid_didNavigateMainFrame(
152 env
, obj
.obj(), jstring_url
.obj(), jstring_base_url
.obj(),
153 details
.is_navigation_to_different_page(), is_fragment_navigation
);
156 void WebContentsObserverAndroid::DidNavigateAnyFrame(
157 const LoadCommittedDetails
& details
,
158 const FrameNavigateParams
& params
) {
159 JNIEnv
* env
= AttachCurrentThread();
160 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
163 ScopedJavaLocalRef
<jstring
> jstring_url(
164 ConvertUTF8ToJavaString(env
, params
.url
.spec()));
165 ScopedJavaLocalRef
<jstring
> jstring_base_url(
166 ConvertUTF8ToJavaString(env
, params
.base_url
.spec()));
167 jboolean jboolean_is_reload
=
168 PageTransitionCoreTypeIs(params
.transition
, PAGE_TRANSITION_RELOAD
);
170 Java_WebContentsObserverAndroid_didNavigateAnyFrame(
171 env
, obj
.obj(), jstring_url
.obj(), jstring_base_url
.obj(),
175 void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
176 RenderFrameHost
* render_frame_host
,
177 const GURL
& validated_url
,
179 bool is_iframe_srcdoc
) {
180 JNIEnv
* env
= AttachCurrentThread();
181 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
184 ScopedJavaLocalRef
<jstring
> jstring_url(
185 ConvertUTF8ToJavaString(env
, validated_url
.spec()));
186 // TODO(dcheng): Does Java really need the parent frame ID? It doesn't appear
187 // to be used at all, and it just adds complexity here.
188 Java_WebContentsObserverAndroid_didStartProvisionalLoadForFrame(
191 render_frame_host
->GetRoutingID(),
192 render_frame_host
->GetParent()
193 ? render_frame_host
->GetParent()->GetRoutingID()
195 !render_frame_host
->GetParent(),
201 void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame(
202 RenderFrameHost
* render_frame_host
,
204 PageTransition transition_type
) {
205 JNIEnv
* env
= AttachCurrentThread();
206 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
209 ScopedJavaLocalRef
<jstring
> jstring_url(
210 ConvertUTF8ToJavaString(env
, url
.spec()));
211 Java_WebContentsObserverAndroid_didCommitProvisionalLoadForFrame(
214 render_frame_host
->GetRoutingID(),
215 !render_frame_host
->GetParent(),
220 void WebContentsObserverAndroid::DidFinishLoad(
221 RenderFrameHost
* render_frame_host
,
222 const GURL
& validated_url
) {
223 JNIEnv
* env
= AttachCurrentThread();
224 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
228 std::string url_string
= validated_url
.spec();
229 NavigationEntry
* entry
=
230 web_contents()->GetController().GetLastCommittedEntry();
231 // Note that GetBaseURLForDataURL is only used by the Android WebView.
232 if (entry
&& !entry
->GetBaseURLForDataURL().is_empty())
233 url_string
= entry
->GetBaseURLForDataURL().possibly_invalid_spec();
235 ScopedJavaLocalRef
<jstring
> jstring_url(
236 ConvertUTF8ToJavaString(env
, url_string
));
237 Java_WebContentsObserverAndroid_didFinishLoad(
240 render_frame_host
->GetRoutingID(),
242 !render_frame_host
->GetParent());
245 void WebContentsObserverAndroid::DocumentLoadedInFrame(
246 RenderFrameHost
* render_frame_host
) {
247 JNIEnv
* env
= AttachCurrentThread();
248 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
251 Java_WebContentsObserverAndroid_documentLoadedInFrame(
252 env
, obj
.obj(), render_frame_host
->GetRoutingID());
255 void WebContentsObserverAndroid::NavigationEntryCommitted(
256 const LoadCommittedDetails
& load_details
) {
257 JNIEnv
* env
= AttachCurrentThread();
258 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
261 Java_WebContentsObserverAndroid_navigationEntryCommitted(env
, obj
.obj());
264 void WebContentsObserverAndroid::DidAttachInterstitialPage() {
265 JNIEnv
* env
= AttachCurrentThread();
266 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
269 Java_WebContentsObserverAndroid_didAttachInterstitialPage(env
, obj
.obj());
272 void WebContentsObserverAndroid::DidDetachInterstitialPage() {
273 JNIEnv
* env
= AttachCurrentThread();
274 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
277 Java_WebContentsObserverAndroid_didDetachInterstitialPage(env
, obj
.obj());
280 void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color
) {
281 JNIEnv
* env
= AttachCurrentThread();
282 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
285 Java_WebContentsObserverAndroid_didChangeThemeColor(env
, obj
.obj(), color
);
288 void WebContentsObserverAndroid::DidFailLoadInternal(
289 bool is_provisional_load
,
292 const base::string16
& description
,
294 JNIEnv
* env
= AttachCurrentThread();
295 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
298 ScopedJavaLocalRef
<jstring
> jstring_error_description(
299 ConvertUTF16ToJavaString(env
, description
));
300 ScopedJavaLocalRef
<jstring
> jstring_url(
301 ConvertUTF8ToJavaString(env
, url
.spec()));
303 Java_WebContentsObserverAndroid_didFailLoad(
308 jstring_error_description
.obj(), jstring_url
.obj());
311 void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() {
312 JNIEnv
* env
= AttachCurrentThread();
313 ScopedJavaLocalRef
<jobject
> obj(weak_java_observer_
.get(env
));
316 Java_WebContentsObserverAndroid_didFirstVisuallyNonEmptyPaint(
320 bool RegisterWebContentsObserverAndroid(JNIEnv
* env
) {
321 return RegisterNativesImpl(env
);
323 } // namespace content