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