aw_web_contents_delegate.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
24using base::android::AttachCurrentThread;
25using base::android::ConvertUTF16ToJavaString;
26using base::android::ConvertUTF8ToJavaString;
27using base::android::ScopedJavaLocalRef;
28using content::FileChooserParams;
29using content::WebContents;
30
31namespace android_webview {
32
33namespace {
34
35// WARNING: these constants are exposed in the public interface Java side, so
36// must remain in sync with what clients are expecting.
37const int kFileChooserModeOpenMultiple = 1 << 0;
38const int kFileChooserModeOpenFolder = 1 << 1;
39
40base::LazyInstance<AwJavaScriptDialogManager>::Leaky
41    g_javascript_dialog_manager = LAZY_INSTANCE_INITIALIZER;
42}
43
44AwWebContentsDelegate::AwWebContentsDelegate(
45    JNIEnv* env,
46    jobject obj)
47    : WebContentsDelegateAndroid(env, obj) {
48}
49
50AwWebContentsDelegate::~AwWebContentsDelegate() {
51}
52
53content::JavaScriptDialogManager*
54AwWebContentsDelegate::GetJavaScriptDialogManager() {
55  return g_javascript_dialog_manager.Pointer();
56}
57
58void 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
74void 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
85void 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
121void 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.
164void AwWebContentsDelegate::WebContentsCreated(
165    WebContents* source_contents,
166    int64 source_frame_id,
167    const base::string16& frame_name,
168    const GURL& target_url,
169    content::WebContents* new_contents) {
170  AwContentsIoThreadClientImpl::RegisterPendingContents(new_contents);
171}
172
173void 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
182void 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
191static 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    GURL url(file_path_str[i]);
208    if (!url.is_valid())
209      continue;
210    base::FilePath path(url.SchemeIsFile() ? url.path() : file_path_str[i]);
211    files.push_back(ui::SelectedFileInfo(path, base::FilePath()));
212  }
213  FileChooserParams::Mode mode;
214  if (mode_flags & kFileChooserModeOpenFolder) {
215    mode = FileChooserParams::UploadFolder;
216  } else if (mode_flags & kFileChooserModeOpenMultiple) {
217    mode = FileChooserParams::OpenMultiple;
218  } else {
219    mode = FileChooserParams::Open;
220  }
221  DVLOG(0) << "File Chooser result: mode = " << mode
222           << ", file paths = " << JoinString(file_path_str, ":");
223  rvh->FilesSelectedInChooser(files, mode);
224}
225
226bool RegisterAwWebContentsDelegate(JNIEnv* env) {
227  return RegisterNativesImpl(env);
228}
229
230}  // namespace android_webview
231