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