• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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).
WebContentsObserverAndroid(JNIEnv * env,jobject obj,WebContents * web_contents)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 
~WebContentsObserverAndroid()38 WebContentsObserverAndroid::~WebContentsObserverAndroid() {
39 }
40 
Init(JNIEnv * env,jobject obj,jobject java_web_contents)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 
Destroy(JNIEnv * env,jobject obj)51 void WebContentsObserverAndroid::Destroy(JNIEnv* env, jobject obj) {
52   delete this;
53 }
54 
WebContentsDestroyed()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 
RenderProcessGone(base::TerminationStatus termination_status)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 
DidStartLoading(RenderViewHost * render_view_host)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 
DidStopLoading(RenderViewHost * render_view_host)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 
DidFailProvisionalLoad(RenderFrameHost * render_frame_host,const GURL & validated_url,int error_code,const base::string16 & error_description)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 
DidFailLoad(RenderFrameHost * render_frame_host,const GURL & validated_url,int error_code,const base::string16 & error_description)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 
DidNavigateMainFrame(const LoadCommittedDetails & details,const FrameNavigateParams & params)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       details.http_status_code);
155 }
156 
DidNavigateAnyFrame(const LoadCommittedDetails & details,const FrameNavigateParams & params)157 void WebContentsObserverAndroid::DidNavigateAnyFrame(
158     const LoadCommittedDetails& details,
159     const FrameNavigateParams& params) {
160   JNIEnv* env = AttachCurrentThread();
161   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
162   if (obj.is_null())
163     return;
164   ScopedJavaLocalRef<jstring> jstring_url(
165       ConvertUTF8ToJavaString(env, params.url.spec()));
166   ScopedJavaLocalRef<jstring> jstring_base_url(
167       ConvertUTF8ToJavaString(env, params.base_url.spec()));
168   jboolean jboolean_is_reload = ui::PageTransitionCoreTypeIs(
169       params.transition, ui::PAGE_TRANSITION_RELOAD);
170 
171   Java_WebContentsObserverAndroid_didNavigateAnyFrame(
172       env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
173       jboolean_is_reload);
174 }
175 
DidStartProvisionalLoadForFrame(RenderFrameHost * render_frame_host,const GURL & validated_url,bool is_error_page,bool is_iframe_srcdoc)176 void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
177     RenderFrameHost* render_frame_host,
178     const GURL& validated_url,
179     bool is_error_page,
180     bool is_iframe_srcdoc) {
181   JNIEnv* env = AttachCurrentThread();
182   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
183   if (obj.is_null())
184     return;
185   ScopedJavaLocalRef<jstring> jstring_url(
186       ConvertUTF8ToJavaString(env, validated_url.spec()));
187   // TODO(dcheng): Does Java really need the parent frame ID? It doesn't appear
188   // to be used at all, and it just adds complexity here.
189   Java_WebContentsObserverAndroid_didStartProvisionalLoadForFrame(
190       env,
191       obj.obj(),
192       render_frame_host->GetRoutingID(),
193       render_frame_host->GetParent()
194           ? render_frame_host->GetParent()->GetRoutingID()
195           : -1,
196       !render_frame_host->GetParent(),
197       jstring_url.obj(),
198       is_error_page,
199       is_iframe_srcdoc);
200 }
201 
DidCommitProvisionalLoadForFrame(RenderFrameHost * render_frame_host,const GURL & url,ui::PageTransition transition_type)202 void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame(
203     RenderFrameHost* render_frame_host,
204     const GURL& url,
205     ui::PageTransition transition_type) {
206   JNIEnv* env = AttachCurrentThread();
207   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
208   if (obj.is_null())
209     return;
210   ScopedJavaLocalRef<jstring> jstring_url(
211       ConvertUTF8ToJavaString(env, url.spec()));
212   Java_WebContentsObserverAndroid_didCommitProvisionalLoadForFrame(
213       env,
214       obj.obj(),
215       render_frame_host->GetRoutingID(),
216       !render_frame_host->GetParent(),
217       jstring_url.obj(),
218       transition_type);
219 }
220 
DidFinishLoad(RenderFrameHost * render_frame_host,const GURL & validated_url)221 void WebContentsObserverAndroid::DidFinishLoad(
222     RenderFrameHost* render_frame_host,
223     const GURL& validated_url) {
224   JNIEnv* env = AttachCurrentThread();
225   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
226   if (obj.is_null())
227     return;
228 
229   std::string url_string = validated_url.spec();
230   NavigationEntry* entry =
231     web_contents()->GetController().GetLastCommittedEntry();
232   // Note that GetBaseURLForDataURL is only used by the Android WebView.
233   if (entry && !entry->GetBaseURLForDataURL().is_empty())
234     url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec();
235 
236   ScopedJavaLocalRef<jstring> jstring_url(
237       ConvertUTF8ToJavaString(env, url_string));
238   Java_WebContentsObserverAndroid_didFinishLoad(
239       env,
240       obj.obj(),
241       render_frame_host->GetRoutingID(),
242       jstring_url.obj(),
243       !render_frame_host->GetParent());
244 }
245 
DocumentLoadedInFrame(RenderFrameHost * render_frame_host)246 void WebContentsObserverAndroid::DocumentLoadedInFrame(
247     RenderFrameHost* render_frame_host) {
248   JNIEnv* env = AttachCurrentThread();
249   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
250   if (obj.is_null())
251     return;
252   Java_WebContentsObserverAndroid_documentLoadedInFrame(
253       env, obj.obj(), render_frame_host->GetRoutingID());
254 }
255 
NavigationEntryCommitted(const LoadCommittedDetails & load_details)256 void WebContentsObserverAndroid::NavigationEntryCommitted(
257     const LoadCommittedDetails& load_details) {
258   JNIEnv* env = AttachCurrentThread();
259   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
260   if (obj.is_null())
261     return;
262   Java_WebContentsObserverAndroid_navigationEntryCommitted(env, obj.obj());
263 }
264 
DidAttachInterstitialPage()265 void WebContentsObserverAndroid::DidAttachInterstitialPage() {
266   JNIEnv* env = AttachCurrentThread();
267   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
268   if (obj.is_null())
269     return;
270   Java_WebContentsObserverAndroid_didAttachInterstitialPage(env, obj.obj());
271 }
272 
DidDetachInterstitialPage()273 void WebContentsObserverAndroid::DidDetachInterstitialPage() {
274   JNIEnv* env = AttachCurrentThread();
275   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
276   if (obj.is_null())
277     return;
278   Java_WebContentsObserverAndroid_didDetachInterstitialPage(env, obj.obj());
279 }
280 
DidChangeThemeColor(SkColor color)281 void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) {
282   JNIEnv* env = AttachCurrentThread();
283   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
284   if (obj.is_null())
285     return;
286   Java_WebContentsObserverAndroid_didChangeThemeColor(env, obj.obj(), color);
287 }
288 
DidFailLoadInternal(bool is_provisional_load,bool is_main_frame,int error_code,const base::string16 & description,const GURL & url)289 void WebContentsObserverAndroid::DidFailLoadInternal(
290     bool is_provisional_load,
291     bool is_main_frame,
292     int error_code,
293     const base::string16& description,
294     const GURL& url) {
295   JNIEnv* env = AttachCurrentThread();
296   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
297   if (obj.is_null())
298     return;
299   ScopedJavaLocalRef<jstring> jstring_error_description(
300       ConvertUTF16ToJavaString(env, description));
301   ScopedJavaLocalRef<jstring> jstring_url(
302       ConvertUTF8ToJavaString(env, url.spec()));
303 
304   Java_WebContentsObserverAndroid_didFailLoad(
305       env, obj.obj(),
306       is_provisional_load,
307       is_main_frame,
308       error_code,
309       jstring_error_description.obj(), jstring_url.obj());
310 }
311 
DidFirstVisuallyNonEmptyPaint()312 void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() {
313   JNIEnv* env = AttachCurrentThread();
314   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
315   if (obj.is_null())
316     return;
317   Java_WebContentsObserverAndroid_didFirstVisuallyNonEmptyPaint(
318       env, obj.obj());
319 }
320 
RegisterWebContentsObserverAndroid(JNIEnv * env)321 bool RegisterWebContentsObserverAndroid(JNIEnv* env) {
322   return RegisterNativesImpl(env);
323 }
324 }  // namespace content
325