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/android/content_view_core_impl.h"
15#include "content/browser/renderer_host/render_widget_host_impl.h"
16#include "content/browser/web_contents/web_contents_impl.h"
17#include "content/public/browser/navigation_details.h"
18#include "content/public/browser/navigation_entry.h"
19#include "jni/WebContentsObserverAndroid_jni.h"
20
21using base::android::AttachCurrentThread;
22using base::android::ScopedJavaLocalRef;
23using base::android::ConvertUTF8ToJavaString;
24using base::android::ConvertUTF16ToJavaString;
25using base::android::HasClass;
26
27namespace content {
28
29WebContentsObserverAndroid::WebContentsObserverAndroid(
30    JNIEnv* env,
31    jobject obj,
32    WebContents* web_contents)
33    : WebContentsObserver(web_contents),
34      weak_java_observer_(env, obj){
35}
36
37WebContentsObserverAndroid::~WebContentsObserverAndroid() {
38}
39
40jint Init(JNIEnv* env, jobject obj, jint native_content_view_core) {
41  ContentViewCore* content_view_core =
42      reinterpret_cast<ContentViewCore*>(native_content_view_core);
43  WebContentsObserverAndroid* native_observer = new WebContentsObserverAndroid(
44      env, obj, content_view_core->GetWebContents());
45  return reinterpret_cast<jint>(native_observer);
46}
47
48void WebContentsObserverAndroid::Destroy(JNIEnv* env, jobject obj) {
49  delete this;
50}
51
52void WebContentsObserverAndroid::WebContentsDestroyed(
53    WebContents* web_contents) {
54  JNIEnv* env = AttachCurrentThread();
55  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
56  if (obj.is_null()) {
57    delete this;
58  } else {
59    // The java side will destroy |this|
60    Java_WebContentsObserverAndroid_detachFromWebContents(env, obj.obj());
61  }
62}
63
64void WebContentsObserverAndroid::DidStartLoading(
65    RenderViewHost* render_view_host) {
66  JNIEnv* env = AttachCurrentThread();
67  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
68  if (obj.is_null())
69    return;
70  ScopedJavaLocalRef<jstring> jstring_url(
71      ConvertUTF8ToJavaString(env, web_contents()->GetURL().spec()));
72  Java_WebContentsObserverAndroid_didStartLoading(
73      env, obj.obj(), jstring_url.obj());
74}
75
76void WebContentsObserverAndroid::DidStopLoading(
77    RenderViewHost* render_view_host) {
78  JNIEnv* env = AttachCurrentThread();
79  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
80  if (obj.is_null())
81    return;
82
83  std::string url_string;
84  NavigationEntry* entry =
85    web_contents()->GetController().GetLastCommittedEntry();
86  // Not that GetBaseURLForDataURL is only used by the Android WebView
87  if (entry && !entry->GetBaseURLForDataURL().is_empty()) {
88    url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec();
89  } else {
90    url_string = web_contents()->GetURL().spec();
91  }
92
93  ScopedJavaLocalRef<jstring> jstring_url(
94      ConvertUTF8ToJavaString(env, url_string));
95  Java_WebContentsObserverAndroid_didStopLoading(
96      env, obj.obj(), jstring_url.obj());
97}
98
99void WebContentsObserverAndroid::DidFailProvisionalLoad(
100    int64 frame_id,
101    bool is_main_frame,
102    const GURL& validated_url,
103    int error_code,
104    const string16& error_description,
105    RenderViewHost* render_view_host) {
106  DidFailLoadInternal(
107        true, is_main_frame, error_code, error_description, validated_url);
108}
109
110void WebContentsObserverAndroid::DidFailLoad(
111    int64 frame_id,
112    const GURL& validated_url,
113    bool is_main_frame,
114    int error_code,
115    const string16& error_description,
116    RenderViewHost* render_view_host) {
117  DidFailLoadInternal(
118        false, is_main_frame, error_code, error_description, validated_url);
119}
120
121void WebContentsObserverAndroid::DidNavigateMainFrame(
122    const LoadCommittedDetails& details,
123    const FrameNavigateParams& params) {
124  JNIEnv* env = AttachCurrentThread();
125  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
126  if (obj.is_null())
127    return;
128  ScopedJavaLocalRef<jstring> jstring_url(
129      ConvertUTF8ToJavaString(env, params.url.spec()));
130  ScopedJavaLocalRef<jstring> jstring_base_url(
131      ConvertUTF8ToJavaString(env, params.base_url.spec()));
132  Java_WebContentsObserverAndroid_didNavigateMainFrame(
133      env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
134      details.is_navigation_to_different_page());
135}
136
137void WebContentsObserverAndroid::DidNavigateAnyFrame(
138    const LoadCommittedDetails& details,
139    const FrameNavigateParams& params) {
140  JNIEnv* env = AttachCurrentThread();
141  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
142  if (obj.is_null())
143    return;
144  ScopedJavaLocalRef<jstring> jstring_url(
145      ConvertUTF8ToJavaString(env, params.url.spec()));
146  ScopedJavaLocalRef<jstring> jstring_base_url(
147      ConvertUTF8ToJavaString(env, params.base_url.spec()));
148  jboolean jboolean_is_reload =
149      PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_RELOAD);
150
151  Java_WebContentsObserverAndroid_didNavigateAnyFrame(
152      env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
153      jboolean_is_reload);
154}
155
156void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
157      int64 frame_id,
158      int64 parent_frame_id,
159      bool is_main_frame,
160      const GURL& validated_url,
161      bool is_error_page,
162      bool is_iframe_srcdoc,
163      RenderViewHost* render_view_host) {
164  JNIEnv* env = AttachCurrentThread();
165  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
166  if (obj.is_null())
167    return;
168  ScopedJavaLocalRef<jstring> jstring_url(
169      ConvertUTF8ToJavaString(env, validated_url.spec()));
170  Java_WebContentsObserverAndroid_didStartProvisionalLoadForFrame(
171      env, obj.obj(), frame_id, parent_frame_id, is_main_frame,
172      jstring_url.obj(), is_error_page, is_iframe_srcdoc);
173}
174
175void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame(
176      int64 frame_id,
177      bool is_main_frame,
178      const GURL& url,
179      PageTransition transition_type,
180      RenderViewHost* render_view_host) {
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, url.spec()));
187  Java_WebContentsObserverAndroid_didCommitProvisionalLoadForFrame(
188      env, obj.obj(), frame_id, is_main_frame, jstring_url.obj(),
189      transition_type);
190}
191
192void WebContentsObserverAndroid::DidFinishLoad(
193    int64 frame_id,
194    const GURL& validated_url,
195    bool is_main_frame,
196    RenderViewHost* render_view_host) {
197  JNIEnv* env = AttachCurrentThread();
198  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
199  if (obj.is_null())
200    return;
201  ScopedJavaLocalRef<jstring> jstring_url(
202      ConvertUTF8ToJavaString(env, validated_url.spec()));
203  Java_WebContentsObserverAndroid_didFinishLoad(
204      env, obj.obj(), frame_id, jstring_url.obj(), is_main_frame);
205}
206
207void WebContentsObserverAndroid::DidChangeVisibleSSLState() {
208  JNIEnv* env = AttachCurrentThread();
209  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
210  if (obj.is_null())
211    return;
212  Java_WebContentsObserverAndroid_didChangeVisibleSSLState(env, obj.obj());
213}
214
215void WebContentsObserverAndroid::DidFailLoadInternal(
216    bool is_provisional_load,
217    bool is_main_frame,
218    int error_code,
219    const string16& description,
220    const GURL& url) {
221  JNIEnv* env = AttachCurrentThread();
222  ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
223  if (obj.is_null())
224    return;
225  ScopedJavaLocalRef<jstring> jstring_error_description(
226      ConvertUTF16ToJavaString(env, description));
227  ScopedJavaLocalRef<jstring> jstring_url(
228      ConvertUTF8ToJavaString(env, url.spec()));
229
230  Java_WebContentsObserverAndroid_didFailLoad(
231      env, obj.obj(),
232      is_provisional_load,
233      is_main_frame,
234      error_code,
235      jstring_error_description.obj(), jstring_url.obj());
236}
237
238bool RegisterWebContentsObserverAndroid(JNIEnv* env) {
239  if (!HasClass(env, kWebContentsObserverAndroidClassPath)) {
240    DLOG(ERROR) << "Unable to find class WebContentsObserverAndroid!";
241    return false;
242  }
243  return RegisterNativesImpl(env);
244}
245}  // namespace content
246