• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "android_webview/native/aw_contents_client_bridge.h"
6 
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/callback.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "jni/AwContentsClientBridge_jni.h"
13 #include "net/cert/x509_certificate.h"
14 #include "url/gurl.h"
15 
16 using base::android::AttachCurrentThread;
17 using base::android::ConvertJavaStringToUTF16;
18 using base::android::ConvertUTF8ToJavaString;
19 using base::android::ConvertUTF16ToJavaString;
20 using base::android::JavaRef;
21 using base::android::ScopedJavaLocalRef;
22 using content::BrowserThread;
23 
24 namespace android_webview {
25 
AwContentsClientBridge(JNIEnv * env,jobject obj)26 AwContentsClientBridge::AwContentsClientBridge(JNIEnv* env, jobject obj)
27     : java_ref_(env, obj) {
28   DCHECK(obj);
29   Java_AwContentsClientBridge_setNativeContentsClientBridge(
30       env, obj, reinterpret_cast<intptr_t>(this));
31 }
32 
~AwContentsClientBridge()33 AwContentsClientBridge::~AwContentsClientBridge() {
34   JNIEnv* env = AttachCurrentThread();
35 
36   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
37   if (obj.is_null())
38     return;
39   // Clear the weak reference from the java peer to the native object since
40   // it is possible that java object lifetime can exceed the AwContens.
41   Java_AwContentsClientBridge_setNativeContentsClientBridge(env, obj.obj(), 0);
42 }
43 
AllowCertificateError(int cert_error,net::X509Certificate * cert,const GURL & request_url,const base::Callback<void (bool)> & callback,bool * cancel_request)44 void AwContentsClientBridge::AllowCertificateError(
45     int cert_error,
46     net::X509Certificate* cert,
47     const GURL& request_url,
48     const base::Callback<void(bool)>& callback,
49     bool* cancel_request) {
50 
51   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52   JNIEnv* env = AttachCurrentThread();
53 
54   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
55   if (obj.is_null())
56     return;
57 
58   std::string der_string;
59   net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_string);
60   ScopedJavaLocalRef<jbyteArray> jcert = base::android::ToJavaByteArray(
61       env,
62       reinterpret_cast<const uint8*>(der_string.data()),
63       der_string.length());
64   ScopedJavaLocalRef<jstring> jurl(ConvertUTF8ToJavaString(
65       env, request_url.spec()));
66   // We need to add the callback before making the call to java side,
67   // as it may do a synchronous callback prior to returning.
68   int request_id = pending_cert_error_callbacks_.Add(
69       new CertErrorCallback(callback));
70   *cancel_request = !Java_AwContentsClientBridge_allowCertificateError(
71       env, obj.obj(), cert_error, jcert.obj(), jurl.obj(), request_id);
72   // if the request is cancelled, then cancel the stored callback
73   if (*cancel_request) {
74     pending_cert_error_callbacks_.Remove(request_id);
75  }
76 }
77 
ProceedSslError(JNIEnv * env,jobject obj,jboolean proceed,jint id)78 void AwContentsClientBridge::ProceedSslError(JNIEnv* env, jobject obj,
79                                              jboolean proceed, jint id) {
80   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
81   CertErrorCallback* callback = pending_cert_error_callbacks_.Lookup(id);
82   if (!callback || callback->is_null()) {
83     LOG(WARNING) << "Ignoring unexpected ssl error proceed callback";
84     return;
85   }
86   callback->Run(proceed);
87   pending_cert_error_callbacks_.Remove(id);
88 }
89 
RunJavaScriptDialog(content::JavaScriptMessageType message_type,const GURL & origin_url,const string16 & message_text,const string16 & default_prompt_text,const content::JavaScriptDialogManager::DialogClosedCallback & callback)90 void AwContentsClientBridge::RunJavaScriptDialog(
91     content::JavaScriptMessageType message_type,
92     const GURL& origin_url,
93     const string16& message_text,
94     const string16& default_prompt_text,
95     const content::JavaScriptDialogManager::DialogClosedCallback& callback) {
96   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
97   JNIEnv* env = AttachCurrentThread();
98 
99   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
100   if (obj.is_null())
101     return;
102 
103   int callback_id = pending_js_dialog_callbacks_.Add(
104       new content::JavaScriptDialogManager::DialogClosedCallback(callback));
105   ScopedJavaLocalRef<jstring> jurl(
106       ConvertUTF8ToJavaString(env, origin_url.spec()));
107   ScopedJavaLocalRef<jstring> jmessage(
108       ConvertUTF16ToJavaString(env, message_text));
109 
110   switch (message_type) {
111     case content::JAVASCRIPT_MESSAGE_TYPE_ALERT:
112       Java_AwContentsClientBridge_handleJsAlert(
113           env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
114       break;
115     case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
116       Java_AwContentsClientBridge_handleJsConfirm(
117           env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
118       break;
119     case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: {
120       ScopedJavaLocalRef<jstring> jdefault_value(
121           ConvertUTF16ToJavaString(env, default_prompt_text));
122       Java_AwContentsClientBridge_handleJsPrompt(env,
123                                                  obj.obj(),
124                                                  jurl.obj(),
125                                                  jmessage.obj(),
126                                                  jdefault_value.obj(),
127                                                  callback_id);
128       break;
129     }
130     default:
131        NOTREACHED();
132   }
133 }
134 
RunBeforeUnloadDialog(const GURL & origin_url,const string16 & message_text,const content::JavaScriptDialogManager::DialogClosedCallback & callback)135 void AwContentsClientBridge::RunBeforeUnloadDialog(
136     const GURL& origin_url,
137     const string16& message_text,
138     const content::JavaScriptDialogManager::DialogClosedCallback& callback) {
139   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140   JNIEnv* env = AttachCurrentThread();
141 
142   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
143   if (obj.is_null())
144     return;
145 
146   int callback_id = pending_js_dialog_callbacks_.Add(
147       new content::JavaScriptDialogManager::DialogClosedCallback(callback));
148   ScopedJavaLocalRef<jstring> jurl(
149       ConvertUTF8ToJavaString(env, origin_url.spec()));
150   ScopedJavaLocalRef<jstring> jmessage(
151       ConvertUTF16ToJavaString(env, message_text));
152 
153   Java_AwContentsClientBridge_handleJsBeforeUnload(
154       env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
155 }
156 
ShouldOverrideUrlLoading(const base::string16 & url)157 bool AwContentsClientBridge::ShouldOverrideUrlLoading(
158     const base::string16& url) {
159   JNIEnv* env = AttachCurrentThread();
160   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
161   if (obj.is_null())
162     return false;
163   ScopedJavaLocalRef<jstring> jurl = ConvertUTF16ToJavaString(env, url);
164   return Java_AwContentsClientBridge_shouldOverrideUrlLoading(
165       env, obj.obj(),
166       jurl.obj());
167 }
168 
ConfirmJsResult(JNIEnv * env,jobject,int id,jstring prompt)169 void AwContentsClientBridge::ConfirmJsResult(JNIEnv* env,
170                                              jobject,
171                                              int id,
172                                              jstring prompt) {
173   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174   content::JavaScriptDialogManager::DialogClosedCallback* callback =
175       pending_js_dialog_callbacks_.Lookup(id);
176   if (!callback) {
177     LOG(WARNING) << "Unexpected JS dialog confirm. " << id;
178     return;
179   }
180   string16 prompt_text;
181   if (prompt) {
182     prompt_text = ConvertJavaStringToUTF16(env, prompt);
183   }
184   callback->Run(true, prompt_text);
185   pending_js_dialog_callbacks_.Remove(id);
186 }
187 
CancelJsResult(JNIEnv *,jobject,int id)188 void AwContentsClientBridge::CancelJsResult(JNIEnv*, jobject, int id) {
189   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
190   content::JavaScriptDialogManager::DialogClosedCallback* callback =
191       pending_js_dialog_callbacks_.Lookup(id);
192   if (!callback) {
193     LOG(WARNING) << "Unexpected JS dialog cancel. " << id;
194     return;
195   }
196   callback->Run(false, string16());
197   pending_js_dialog_callbacks_.Remove(id);
198 }
199 
RegisterAwContentsClientBridge(JNIEnv * env)200 bool RegisterAwContentsClientBridge(JNIEnv* env) {
201   return RegisterNativesImpl(env) >= 0;
202 }
203 
204 }  // namespace android_webview
205