Home | History | Annotate | Download | only in native
      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 
     26 AwContentsClientBridge::AwContentsClientBridge(JNIEnv* env, jobject obj)
     27     : java_ref_(env, obj) {
     28   DCHECK(obj);
     29   Java_AwContentsClientBridge_setNativeContentsClientBridge(
     30       env, obj, reinterpret_cast<jint>(this));
     31 }
     32 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    200 bool RegisterAwContentsClientBridge(JNIEnv* env) {
    201   return RegisterNativesImpl(env) >= 0;
    202 }
    203 
    204 }  // namespace android_webview
    205