1 // Copyright (c) 2013 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 "android_webview/native/aw_contents_client_bridge.h"
7 #include "android_webview/common/devtools_instrumentation.h"
8 #include "base/android/jni_android.h"
9 #include "base/android/jni_array.h"
10 #include "base/android/jni_string.h"
11 #include "base/callback.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "jni/AwContentsClientBridge_jni.h"
14 #include "net/cert/x509_certificate.h"
17 using base::android::AttachCurrentThread
;
18 using base::android::ConvertJavaStringToUTF16
;
19 using base::android::ConvertUTF8ToJavaString
;
20 using base::android::ConvertUTF16ToJavaString
;
21 using base::android::JavaRef
;
22 using base::android::ScopedJavaLocalRef
;
23 using content::BrowserThread
;
25 namespace android_webview
{
27 AwContentsClientBridge::AwContentsClientBridge(JNIEnv
* env
, jobject obj
)
28 : java_ref_(env
, obj
) {
30 Java_AwContentsClientBridge_setNativeContentsClientBridge(
31 env
, obj
, reinterpret_cast<intptr_t>(this));
34 AwContentsClientBridge::~AwContentsClientBridge() {
35 JNIEnv
* env
= AttachCurrentThread();
37 ScopedJavaLocalRef
<jobject
> obj
= java_ref_
.get(env
);
40 // Clear the weak reference from the java peer to the native object since
41 // it is possible that java object lifetime can exceed the AwContens.
42 Java_AwContentsClientBridge_setNativeContentsClientBridge(env
, obj
.obj(), 0);
45 void AwContentsClientBridge::AllowCertificateError(
47 net::X509Certificate
* cert
,
48 const GURL
& request_url
,
49 const base::Callback
<void(bool)>& callback
,
50 bool* cancel_request
) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
53 JNIEnv
* env
= AttachCurrentThread();
55 ScopedJavaLocalRef
<jobject
> obj
= java_ref_
.get(env
);
59 std::string der_string
;
60 net::X509Certificate::GetDEREncoded(cert
->os_cert_handle(), &der_string
);
61 ScopedJavaLocalRef
<jbyteArray
> jcert
= base::android::ToJavaByteArray(
63 reinterpret_cast<const uint8
*>(der_string
.data()),
65 ScopedJavaLocalRef
<jstring
> jurl(ConvertUTF8ToJavaString(
66 env
, request_url
.spec()));
67 // We need to add the callback before making the call to java side,
68 // as it may do a synchronous callback prior to returning.
69 int request_id
= pending_cert_error_callbacks_
.Add(
70 new CertErrorCallback(callback
));
71 *cancel_request
= !Java_AwContentsClientBridge_allowCertificateError(
72 env
, obj
.obj(), cert_error
, jcert
.obj(), jurl
.obj(), request_id
);
73 // if the request is cancelled, then cancel the stored callback
74 if (*cancel_request
) {
75 pending_cert_error_callbacks_
.Remove(request_id
);
79 void AwContentsClientBridge::ProceedSslError(JNIEnv
* env
, jobject obj
,
80 jboolean proceed
, jint id
) {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
82 CertErrorCallback
* callback
= pending_cert_error_callbacks_
.Lookup(id
);
83 if (!callback
|| callback
->is_null()) {
84 LOG(WARNING
) << "Ignoring unexpected ssl error proceed callback";
87 callback
->Run(proceed
);
88 pending_cert_error_callbacks_
.Remove(id
);
91 void AwContentsClientBridge::RunJavaScriptDialog(
92 content::JavaScriptMessageType message_type
,
93 const GURL
& origin_url
,
94 const base::string16
& message_text
,
95 const base::string16
& default_prompt_text
,
96 const content::JavaScriptDialogManager::DialogClosedCallback
& callback
) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
98 JNIEnv
* env
= AttachCurrentThread();
100 ScopedJavaLocalRef
<jobject
> obj
= java_ref_
.get(env
);
104 int callback_id
= pending_js_dialog_callbacks_
.Add(
105 new content::JavaScriptDialogManager::DialogClosedCallback(callback
));
106 ScopedJavaLocalRef
<jstring
> jurl(
107 ConvertUTF8ToJavaString(env
, origin_url
.spec()));
108 ScopedJavaLocalRef
<jstring
> jmessage(
109 ConvertUTF16ToJavaString(env
, message_text
));
111 switch (message_type
) {
112 case content::JAVASCRIPT_MESSAGE_TYPE_ALERT
: {
113 devtools_instrumentation::ScopedEmbedderCallbackTask("onJsAlert");
114 Java_AwContentsClientBridge_handleJsAlert(
115 env
, obj
.obj(), jurl
.obj(), jmessage
.obj(), callback_id
);
118 case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM
: {
119 devtools_instrumentation::ScopedEmbedderCallbackTask("onJsConfirm");
120 Java_AwContentsClientBridge_handleJsConfirm(
121 env
, obj
.obj(), jurl
.obj(), jmessage
.obj(), callback_id
);
124 case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT
: {
125 ScopedJavaLocalRef
<jstring
> jdefault_value(
126 ConvertUTF16ToJavaString(env
, default_prompt_text
));
127 devtools_instrumentation::ScopedEmbedderCallbackTask("onJsPrompt");
128 Java_AwContentsClientBridge_handleJsPrompt(env
,
132 jdefault_value
.obj(),
141 void AwContentsClientBridge::RunBeforeUnloadDialog(
142 const GURL
& origin_url
,
143 const base::string16
& message_text
,
144 const content::JavaScriptDialogManager::DialogClosedCallback
& callback
) {
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
146 JNIEnv
* env
= AttachCurrentThread();
148 ScopedJavaLocalRef
<jobject
> obj
= java_ref_
.get(env
);
152 int callback_id
= pending_js_dialog_callbacks_
.Add(
153 new content::JavaScriptDialogManager::DialogClosedCallback(callback
));
154 ScopedJavaLocalRef
<jstring
> jurl(
155 ConvertUTF8ToJavaString(env
, origin_url
.spec()));
156 ScopedJavaLocalRef
<jstring
> jmessage(
157 ConvertUTF16ToJavaString(env
, message_text
));
159 devtools_instrumentation::ScopedEmbedderCallbackTask("onJsBeforeUnload");
160 Java_AwContentsClientBridge_handleJsBeforeUnload(
161 env
, obj
.obj(), jurl
.obj(), jmessage
.obj(), callback_id
);
164 bool AwContentsClientBridge::ShouldOverrideUrlLoading(
165 const base::string16
& url
) {
166 JNIEnv
* env
= AttachCurrentThread();
167 ScopedJavaLocalRef
<jobject
> obj
= java_ref_
.get(env
);
170 ScopedJavaLocalRef
<jstring
> jurl
= ConvertUTF16ToJavaString(env
, url
);
171 devtools_instrumentation::ScopedEmbedderCallbackTask(
172 "shouldOverrideUrlLoading");
173 return Java_AwContentsClientBridge_shouldOverrideUrlLoading(
178 void AwContentsClientBridge::ConfirmJsResult(JNIEnv
* env
,
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
183 content::JavaScriptDialogManager::DialogClosedCallback
* callback
=
184 pending_js_dialog_callbacks_
.Lookup(id
);
186 LOG(WARNING
) << "Unexpected JS dialog confirm. " << id
;
189 base::string16 prompt_text
;
191 prompt_text
= ConvertJavaStringToUTF16(env
, prompt
);
193 callback
->Run(true, prompt_text
);
194 pending_js_dialog_callbacks_
.Remove(id
);
197 void AwContentsClientBridge::CancelJsResult(JNIEnv
*, jobject
, int id
) {
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
199 content::JavaScriptDialogManager::DialogClosedCallback
* callback
=
200 pending_js_dialog_callbacks_
.Lookup(id
);
202 LOG(WARNING
) << "Unexpected JS dialog cancel. " << id
;
205 callback
->Run(false, base::string16());
206 pending_js_dialog_callbacks_
.Remove(id
);
209 bool RegisterAwContentsClientBridge(JNIEnv
* env
) {
210 return RegisterNativesImpl(env
) >= 0;
213 } // namespace android_webview