Home | History | Annotate | Download | only in native
      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 "android_webview/native/aw_web_contents_delegate.h"
      6 
      7 #include "android_webview/browser/aw_javascript_dialog_manager.h"
      8 #include "android_webview/browser/find_helper.h"
      9 #include "android_webview/native/aw_contents.h"
     10 #include "base/android/jni_array.h"
     11 #include "base/android/jni_string.h"
     12 #include "base/android/scoped_java_ref.h"
     13 #include "base/lazy_instance.h"
     14 #include "base/message_loop/message_loop.h"
     15 #include "base/strings/string_util.h"
     16 #include "content/public/browser/render_process_host.h"
     17 #include "content/public/browser/render_view_host.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "content/public/common/file_chooser_params.h"
     20 #include "jni/AwWebContentsDelegate_jni.h"
     21 #include "ui/shell_dialogs/selected_file_info.h"
     22 
     23 using base::android::AttachCurrentThread;
     24 using base::android::ConvertUTF16ToJavaString;
     25 using base::android::ConvertUTF8ToJavaString;
     26 using base::android::ScopedJavaLocalRef;
     27 using content::FileChooserParams;
     28 using content::WebContents;
     29 
     30 namespace android_webview {
     31 
     32 namespace {
     33 
     34 // WARNING: these constants are exposed in the public interface Java side, so
     35 // must remain in sync with what clients are expecting.
     36 const int kFileChooserModeOpenMultiple = 1 << 0;
     37 const int kFileChooserModeOpenFolder = 1 << 1;
     38 
     39 base::LazyInstance<AwJavaScriptDialogManager>::Leaky
     40     g_javascript_dialog_manager = LAZY_INSTANCE_INITIALIZER;
     41 }
     42 
     43 AwWebContentsDelegate::AwWebContentsDelegate(
     44     JNIEnv* env,
     45     jobject obj)
     46     : WebContentsDelegateAndroid(env, obj) {
     47 }
     48 
     49 AwWebContentsDelegate::~AwWebContentsDelegate() {
     50 }
     51 
     52 content::JavaScriptDialogManager*
     53 AwWebContentsDelegate::GetJavaScriptDialogManager() {
     54   return g_javascript_dialog_manager.Pointer();
     55 }
     56 
     57 void AwWebContentsDelegate::FindReply(WebContents* web_contents,
     58                                       int request_id,
     59                                       int number_of_matches,
     60                                       const gfx::Rect& selection_rect,
     61                                       int active_match_ordinal,
     62                                       bool final_update) {
     63   AwContents* aw_contents = AwContents::FromWebContents(web_contents);
     64   if (!aw_contents)
     65     return;
     66 
     67   aw_contents->GetFindHelper()->HandleFindReply(request_id,
     68                                                 number_of_matches,
     69                                                 active_match_ordinal,
     70                                                 final_update);
     71 }
     72 
     73 void AwWebContentsDelegate::CanDownload(
     74     content::RenderViewHost* source,
     75     int request_id,
     76     const std::string& request_method,
     77     const base::Callback<void(bool)>& callback) {
     78   // Android webview intercepts download in its resource dispatcher host
     79   // delegate, so should not reach here.
     80   NOTREACHED();
     81   callback.Run(false);
     82 }
     83 
     84 void AwWebContentsDelegate::RunFileChooser(WebContents* web_contents,
     85                                            const FileChooserParams& params) {
     86   JNIEnv* env = AttachCurrentThread();
     87   ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
     88   if (!java_delegate.obj())
     89     return;
     90 
     91   int mode_flags = 0;
     92   if (params.mode == FileChooserParams::OpenMultiple) {
     93     mode_flags |= kFileChooserModeOpenMultiple;
     94   } else if (params.mode == FileChooserParams::UploadFolder) {
     95     // Folder implies multiple in Chrome.
     96     mode_flags |= kFileChooserModeOpenMultiple | kFileChooserModeOpenFolder;
     97   } else if (params.mode == FileChooserParams::Save) {
     98     // Save not supported, so cancel it.
     99     web_contents->GetRenderViewHost()->FilesSelectedInChooser(
    100          std::vector<ui::SelectedFileInfo>(),
    101          params.mode);
    102     return;
    103   } else {
    104     DCHECK_EQ(FileChooserParams::Open, params.mode);
    105   }
    106   Java_AwWebContentsDelegate_runFileChooser(env,
    107       java_delegate.obj(),
    108       web_contents->GetRenderProcessHost()->GetID(),
    109       web_contents->GetRenderViewHost()->GetRoutingID(),
    110       mode_flags,
    111       ConvertUTF16ToJavaString(env,
    112         JoinString(params.accept_types, ',')).obj(),
    113       params.title.empty() ? NULL :
    114           ConvertUTF16ToJavaString(env, params.title).obj(),
    115       params.default_file_name.empty() ? NULL :
    116           ConvertUTF8ToJavaString(env, params.default_file_name.value()).obj(),
    117       params.capture);
    118 }
    119 
    120 void AwWebContentsDelegate::AddNewContents(WebContents* source,
    121                                            WebContents* new_contents,
    122                                            WindowOpenDisposition disposition,
    123                                            const gfx::Rect& initial_pos,
    124                                            bool user_gesture,
    125                                            bool* was_blocked) {
    126   JNIEnv* env = AttachCurrentThread();
    127 
    128   bool is_dialog = disposition == NEW_POPUP;
    129   ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
    130   bool create_popup = false;
    131 
    132   if (java_delegate.obj()) {
    133     create_popup = Java_AwWebContentsDelegate_addNewContents(env,
    134         java_delegate.obj(), is_dialog, user_gesture);
    135   }
    136 
    137   if (create_popup) {
    138     // The embedder would like to display the popup and we will receive
    139     // a callback from them later with an AwContents to use to display
    140     // it. The source AwContents takes ownership of the new WebContents
    141     // until then, and when the callback is made we will swap the WebContents
    142     // out into the new AwContents.
    143     AwContents::FromWebContents(source)->SetPendingWebContentsForPopup(
    144         make_scoped_ptr(new_contents));
    145     // Hide the WebContents for the pop up now, we will show it again
    146     // when the user calls us back with an AwContents to use to show it.
    147     new_contents->WasHidden();
    148   } else {
    149     // The embedder has forgone their chance to display this popup
    150     // window, so we're done with the WebContents now. We use
    151     // DeleteSoon as WebContentsImpl may call methods on |new_contents|
    152     // after this method returns.
    153     base::MessageLoop::current()->DeleteSoon(FROM_HERE, new_contents);
    154   }
    155 
    156   if (was_blocked) {
    157     *was_blocked = !create_popup;
    158   }
    159 }
    160 
    161 void AwWebContentsDelegate::CloseContents(WebContents* source) {
    162   JNIEnv* env = AttachCurrentThread();
    163 
    164   ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
    165   if (java_delegate.obj()) {
    166     Java_AwWebContentsDelegate_closeContents(env, java_delegate.obj());
    167   }
    168 }
    169 
    170 void AwWebContentsDelegate::ActivateContents(WebContents* contents) {
    171   JNIEnv* env = AttachCurrentThread();
    172 
    173   ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
    174   if (java_delegate.obj()) {
    175     Java_AwWebContentsDelegate_activateContents(env, java_delegate.obj());
    176   }
    177 }
    178 
    179 static void FilesSelectedInChooser(
    180     JNIEnv* env, jclass clazz,
    181     jint process_id, jint render_id, jint mode_flags,
    182     jobjectArray file_paths) {
    183   content::RenderViewHost* rvh = content::RenderViewHost::FromID(process_id,
    184                                                                  render_id);
    185   if (!rvh)
    186     return;
    187 
    188   std::vector<std::string> file_path_str;
    189   // Note file_paths maybe NULL, but this will just yield a zero-length vector.
    190   base::android::AppendJavaStringArrayToStringVector(env, file_paths,
    191                                                      &file_path_str);
    192   std::vector<ui::SelectedFileInfo> files;
    193   files.reserve(file_path_str.size());
    194   for (size_t i = 0; i < file_path_str.size(); ++i) {
    195     files.push_back(ui::SelectedFileInfo(base::FilePath(file_path_str[i]),
    196                                          base::FilePath()));
    197   }
    198   FileChooserParams::Mode mode;
    199   if (mode_flags & kFileChooserModeOpenFolder) {
    200     mode = FileChooserParams::UploadFolder;
    201   } else if (mode_flags & kFileChooserModeOpenMultiple) {
    202     mode = FileChooserParams::OpenMultiple;
    203   } else {
    204     mode = FileChooserParams::Open;
    205   }
    206   LOG(INFO) << "File Chooser result: mode = " << mode
    207             << ", file paths = " << JoinString(file_path_str, ":");
    208   rvh->FilesSelectedInChooser(files, mode);
    209 }
    210 
    211 bool RegisterAwWebContentsDelegate(JNIEnv* env) {
    212   return RegisterNativesImpl(env);
    213 }
    214 
    215 }  // namespace android_webview
    216