237abd6f6e34180d1e28ae36b23abba5bc5cdeb5
[platform/framework/web/crosswalk.git] / src / content / browser / android / web_contents_observer_android.cc
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/WebContentsObserverAndroid_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_WebContentsObserverAndroid_detachFromWebContents(env, obj.obj());
63   }
64 }
65
66 void WebContentsObserverAndroid::RenderProcessGone(
67     base::TerminationStatus termination_status) {
68   JNIEnv* env = AttachCurrentThread();
69   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
70   if (obj.is_null())
71     return;
72   jboolean was_oom_protected =
73       termination_status == base::TERMINATION_STATUS_OOM_PROTECTED;
74   Java_WebContentsObserverAndroid_renderProcessGone(
75       env, obj.obj(), was_oom_protected);
76 }
77
78 void WebContentsObserverAndroid::DidStartLoading(
79     RenderViewHost* render_view_host) {
80   JNIEnv* env = AttachCurrentThread();
81   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
82   if (obj.is_null())
83     return;
84   ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
85       env, web_contents()->GetVisibleURL().spec()));
86   Java_WebContentsObserverAndroid_didStartLoading(
87       env, obj.obj(), jstring_url.obj());
88 }
89
90 void WebContentsObserverAndroid::DidStopLoading(
91     RenderViewHost* render_view_host) {
92   JNIEnv* env = AttachCurrentThread();
93   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
94   if (obj.is_null())
95     return;
96   ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
97       env, web_contents()->GetLastCommittedURL().spec()));
98   Java_WebContentsObserverAndroid_didStopLoading(
99       env, obj.obj(), jstring_url.obj());
100 }
101
102 void WebContentsObserverAndroid::DidFailProvisionalLoad(
103     RenderFrameHost* render_frame_host,
104     const GURL& validated_url,
105     int error_code,
106     const base::string16& error_description) {
107   DidFailLoadInternal(true,
108                       !render_frame_host->GetParent(),
109                       error_code,
110                       error_description,
111                       validated_url);
112 }
113
114 void WebContentsObserverAndroid::DidFailLoad(
115     RenderFrameHost* render_frame_host,
116     const GURL& validated_url,
117     int error_code,
118     const base::string16& error_description) {
119   DidFailLoadInternal(false,
120                       !render_frame_host->GetParent(),
121                       error_code,
122                       error_description,
123                       validated_url);
124 }
125
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));
131   if (obj.is_null())
132     return;
133   ScopedJavaLocalRef<jstring> jstring_url(
134       ConvertUTF8ToJavaString(env, params.url.spec()));
135   ScopedJavaLocalRef<jstring> jstring_base_url(
136       ConvertUTF8ToJavaString(env, params.base_url.spec()));
137
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);
144
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);
154 }
155
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));
161   if (obj.is_null())
162     return;
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 = ui::PageTransitionCoreTypeIs(
168       params.transition, ui::PAGE_TRANSITION_RELOAD);
169
170   Java_WebContentsObserverAndroid_didNavigateAnyFrame(
171       env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
172       jboolean_is_reload);
173 }
174
175 void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
176     RenderFrameHost* render_frame_host,
177     const GURL& validated_url,
178     bool is_error_page,
179     bool is_iframe_srcdoc) {
180   JNIEnv* env = AttachCurrentThread();
181   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
182   if (obj.is_null())
183     return;
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(
189       env,
190       obj.obj(),
191       render_frame_host->GetRoutingID(),
192       render_frame_host->GetParent()
193           ? render_frame_host->GetParent()->GetRoutingID()
194           : -1,
195       !render_frame_host->GetParent(),
196       jstring_url.obj(),
197       is_error_page,
198       is_iframe_srcdoc);
199 }
200
201 void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame(
202     RenderFrameHost* render_frame_host,
203     const GURL& url,
204     ui::PageTransition transition_type) {
205   JNIEnv* env = AttachCurrentThread();
206   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
207   if (obj.is_null())
208     return;
209   ScopedJavaLocalRef<jstring> jstring_url(
210       ConvertUTF8ToJavaString(env, url.spec()));
211   Java_WebContentsObserverAndroid_didCommitProvisionalLoadForFrame(
212       env,
213       obj.obj(),
214       render_frame_host->GetRoutingID(),
215       !render_frame_host->GetParent(),
216       jstring_url.obj(),
217       transition_type);
218 }
219
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));
225   if (obj.is_null())
226     return;
227
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();
234
235   ScopedJavaLocalRef<jstring> jstring_url(
236       ConvertUTF8ToJavaString(env, url_string));
237   Java_WebContentsObserverAndroid_didFinishLoad(
238       env,
239       obj.obj(),
240       render_frame_host->GetRoutingID(),
241       jstring_url.obj(),
242       !render_frame_host->GetParent());
243 }
244
245 void WebContentsObserverAndroid::DocumentLoadedInFrame(
246     RenderFrameHost* render_frame_host) {
247   JNIEnv* env = AttachCurrentThread();
248   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
249   if (obj.is_null())
250     return;
251   Java_WebContentsObserverAndroid_documentLoadedInFrame(
252       env, obj.obj(), render_frame_host->GetRoutingID());
253 }
254
255 void WebContentsObserverAndroid::NavigationEntryCommitted(
256     const LoadCommittedDetails& load_details) {
257   JNIEnv* env = AttachCurrentThread();
258   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
259   if (obj.is_null())
260     return;
261   Java_WebContentsObserverAndroid_navigationEntryCommitted(env, obj.obj());
262 }
263
264 void WebContentsObserverAndroid::DidAttachInterstitialPage() {
265   JNIEnv* env = AttachCurrentThread();
266   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
267   if (obj.is_null())
268     return;
269   Java_WebContentsObserverAndroid_didAttachInterstitialPage(env, obj.obj());
270 }
271
272 void WebContentsObserverAndroid::DidDetachInterstitialPage() {
273   JNIEnv* env = AttachCurrentThread();
274   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
275   if (obj.is_null())
276     return;
277   Java_WebContentsObserverAndroid_didDetachInterstitialPage(env, obj.obj());
278 }
279
280 void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) {
281   JNIEnv* env = AttachCurrentThread();
282   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
283   if (obj.is_null())
284     return;
285   Java_WebContentsObserverAndroid_didChangeThemeColor(env, obj.obj(), color);
286 }
287
288 void WebContentsObserverAndroid::DidFailLoadInternal(
289     bool is_provisional_load,
290     bool is_main_frame,
291     int error_code,
292     const base::string16& description,
293     const GURL& url) {
294   JNIEnv* env = AttachCurrentThread();
295   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
296   if (obj.is_null())
297     return;
298   ScopedJavaLocalRef<jstring> jstring_error_description(
299       ConvertUTF16ToJavaString(env, description));
300   ScopedJavaLocalRef<jstring> jstring_url(
301       ConvertUTF8ToJavaString(env, url.spec()));
302
303   Java_WebContentsObserverAndroid_didFailLoad(
304       env, obj.obj(),
305       is_provisional_load,
306       is_main_frame,
307       error_code,
308       jstring_error_description.obj(), jstring_url.obj());
309 }
310
311 void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() {
312   JNIEnv* env = AttachCurrentThread();
313   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
314   if (obj.is_null())
315     return;
316   Java_WebContentsObserverAndroid_didFirstVisuallyNonEmptyPaint(
317       env, obj.obj());
318 }
319
320 bool RegisterWebContentsObserverAndroid(JNIEnv* env) {
321   return RegisterNativesImpl(env);
322 }
323 }  // namespace content