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