Home | History | Annotate | Download | only in android
      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 "chrome/browser/android/chrome_web_contents_delegate_android.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_string.h"
      9 #include "base/command_line.h"
     10 #include "chrome/browser/chrome_notification_types.h"
     11 #include "chrome/browser/file_select_helper.h"
     12 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
     13 #include "chrome/browser/media/protected_media_identifier_permission_context.h"
     14 #include "chrome/browser/media/protected_media_identifier_permission_context_factory.h"
     15 #include "chrome/browser/prerender/prerender_manager.h"
     16 #include "chrome/browser/prerender/prerender_manager_factory.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
     19 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
     20 #include "chrome/browser/ui/browser_navigator.h"
     21 #include "chrome/browser/ui/find_bar/find_notification_details.h"
     22 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
     23 #include "chrome/browser/ui/tab_helpers.h"
     24 #include "chrome/common/chrome_switches.h"
     25 #include "content/public/browser/notification_details.h"
     26 #include "content/public/browser/notification_service.h"
     27 #include "content/public/browser/notification_source.h"
     28 #include "content/public/browser/render_process_host.h"
     29 #include "content/public/browser/render_view_host.h"
     30 #include "content/public/browser/web_contents.h"
     31 #include "content/public/common/file_chooser_params.h"
     32 #include "jni/ChromeWebContentsDelegateAndroid_jni.h"
     33 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
     34 #include "ui/gfx/rect.h"
     35 #include "ui/gfx/rect_f.h"
     36 
     37 #if defined(ENABLE_PLUGINS)
     38 #include "chrome/browser/pepper_broker_infobar_delegate.h"
     39 #endif
     40 
     41 using base::android::AttachCurrentThread;
     42 using base::android::ScopedJavaLocalRef;
     43 using content::FileChooserParams;
     44 using content::WebContents;
     45 
     46 namespace {
     47 
     48 ScopedJavaLocalRef<jobject> CreateJavaRectF(
     49     JNIEnv* env,
     50     const gfx::RectF& rect) {
     51   return ScopedJavaLocalRef<jobject>(
     52       Java_ChromeWebContentsDelegateAndroid_createRectF(env,
     53                                                         rect.x(),
     54                                                         rect.y(),
     55                                                         rect.right(),
     56                                                         rect.bottom()));
     57 }
     58 
     59 ScopedJavaLocalRef<jobject> CreateJavaRect(
     60     JNIEnv* env,
     61     const gfx::Rect& rect) {
     62   return ScopedJavaLocalRef<jobject>(
     63       Java_ChromeWebContentsDelegateAndroid_createRect(
     64           env,
     65           static_cast<int>(rect.x()),
     66           static_cast<int>(rect.y()),
     67           static_cast<int>(rect.right()),
     68           static_cast<int>(rect.bottom())));
     69 }
     70 
     71 }  // anonymous namespace
     72 
     73 namespace chrome {
     74 namespace android {
     75 
     76 ChromeWebContentsDelegateAndroid::ChromeWebContentsDelegateAndroid(JNIEnv* env,
     77                                                                    jobject obj)
     78     : WebContentsDelegateAndroid(env, obj) {
     79 }
     80 
     81 ChromeWebContentsDelegateAndroid::~ChromeWebContentsDelegateAndroid() {
     82   notification_registrar_.RemoveAll();
     83 }
     84 
     85 // Register native methods.
     86 bool RegisterChromeWebContentsDelegateAndroid(JNIEnv* env) {
     87   return RegisterNativesImpl(env);
     88 }
     89 
     90 void ChromeWebContentsDelegateAndroid::LoadingStateChanged(
     91     WebContents* source, bool to_different_document) {
     92   bool has_stopped = source == NULL || !source->IsLoading();
     93   WebContentsDelegateAndroid::LoadingStateChanged(
     94       source, to_different_document);
     95   LoadProgressChanged(source, has_stopped ? 1 : 0);
     96 }
     97 
     98 void ChromeWebContentsDelegateAndroid::RunFileChooser(
     99     WebContents* web_contents,
    100     const FileChooserParams& params) {
    101   FileSelectHelper::RunFileChooser(web_contents, params);
    102 }
    103 
    104 void ChromeWebContentsDelegateAndroid::CloseContents(
    105     WebContents* web_contents) {
    106   // Prevent dangling registrations assigned to closed web contents.
    107   if (notification_registrar_.IsRegistered(this,
    108       chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
    109       content::Source<WebContents>(web_contents))) {
    110     notification_registrar_.Remove(this,
    111         chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
    112         content::Source<WebContents>(web_contents));
    113   }
    114 
    115   WebContentsDelegateAndroid::CloseContents(web_contents);
    116 }
    117 
    118 void ChromeWebContentsDelegateAndroid::Observe(
    119     int type,
    120     const content::NotificationSource& source,
    121     const content::NotificationDetails& details) {
    122   switch (type) {
    123     case chrome::NOTIFICATION_FIND_RESULT_AVAILABLE:
    124       OnFindResultAvailable(
    125           content::Source<WebContents>(source).ptr(),
    126           content::Details<FindNotificationDetails>(details).ptr());
    127       break;
    128     default:
    129       NOTREACHED() << "Unexpected notification: " << type;
    130       break;
    131   }
    132 }
    133 
    134 void ChromeWebContentsDelegateAndroid::FindReply(
    135     WebContents* web_contents,
    136     int request_id,
    137     int number_of_matches,
    138     const gfx::Rect& selection_rect,
    139     int active_match_ordinal,
    140     bool final_update) {
    141   if (!notification_registrar_.IsRegistered(this,
    142       chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
    143       content::Source<WebContents>(web_contents))) {
    144     notification_registrar_.Add(this,
    145         chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
    146         content::Source<WebContents>(web_contents));
    147   }
    148 
    149   FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents);
    150   find_tab_helper->HandleFindReply(request_id,
    151                                    number_of_matches,
    152                                    selection_rect,
    153                                    active_match_ordinal,
    154                                    final_update);
    155 }
    156 
    157 void ChromeWebContentsDelegateAndroid::OnFindResultAvailable(
    158     WebContents* web_contents,
    159     const FindNotificationDetails* find_result) {
    160   JNIEnv* env = base::android::AttachCurrentThread();
    161   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
    162   if (obj.is_null())
    163     return;
    164 
    165   ScopedJavaLocalRef<jobject> selection_rect = CreateJavaRect(
    166       env, find_result->selection_rect());
    167 
    168   // Create the details object.
    169   ScopedJavaLocalRef<jobject> details_object =
    170       Java_ChromeWebContentsDelegateAndroid_createFindNotificationDetails(
    171           env,
    172           find_result->number_of_matches(),
    173           selection_rect.obj(),
    174           find_result->active_match_ordinal(),
    175           find_result->final_update());
    176 
    177   Java_ChromeWebContentsDelegateAndroid_onFindResultAvailable(
    178       env,
    179       obj.obj(),
    180       details_object.obj());
    181 }
    182 
    183 void ChromeWebContentsDelegateAndroid::FindMatchRectsReply(
    184     WebContents* web_contents,
    185     int version,
    186     const std::vector<gfx::RectF>& rects,
    187     const gfx::RectF& active_rect) {
    188   JNIEnv* env = base::android::AttachCurrentThread();
    189   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
    190   if (obj.is_null())
    191     return;
    192 
    193   // Create the details object.
    194   ScopedJavaLocalRef<jobject> details_object =
    195       Java_ChromeWebContentsDelegateAndroid_createFindMatchRectsDetails(
    196           env,
    197           version,
    198           rects.size(),
    199           CreateJavaRectF(env, active_rect).obj());
    200 
    201   // Add the rects
    202   for (size_t i = 0; i < rects.size(); ++i) {
    203       Java_ChromeWebContentsDelegateAndroid_setMatchRectByIndex(
    204           env,
    205           details_object.obj(),
    206           i,
    207           CreateJavaRectF(env, rects[i]).obj());
    208   }
    209 
    210   Java_ChromeWebContentsDelegateAndroid_onFindMatchRectsAvailable(
    211       env,
    212       obj.obj(),
    213       details_object.obj());
    214 }
    215 
    216 content::JavaScriptDialogManager*
    217 ChromeWebContentsDelegateAndroid::GetJavaScriptDialogManager() {
    218   return GetJavaScriptDialogManagerInstance();
    219 }
    220 
    221 void ChromeWebContentsDelegateAndroid::RequestMediaAccessPermission(
    222     content::WebContents* web_contents,
    223     const content::MediaStreamRequest& request,
    224     const content::MediaResponseCallback& callback) {
    225   MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
    226       web_contents, request, callback, NULL);
    227 }
    228 
    229 bool ChromeWebContentsDelegateAndroid::CheckMediaAccessPermission(
    230     content::WebContents* web_contents,
    231     const GURL& security_origin,
    232     content::MediaStreamType type) {
    233   return MediaCaptureDevicesDispatcher::GetInstance()
    234       ->CheckMediaAccessPermission(web_contents, security_origin, type);
    235 }
    236 
    237 bool ChromeWebContentsDelegateAndroid::RequestPpapiBrokerPermission(
    238     WebContents* web_contents,
    239     const GURL& url,
    240     const base::FilePath& plugin_path,
    241     const base::Callback<void(bool)>& callback) {
    242 #if defined(ENABLE_PLUGINS)
    243     PepperBrokerInfoBarDelegate::Create(
    244         web_contents, url, plugin_path, callback);
    245     return true;
    246 #else
    247     return false;
    248 #endif
    249 }
    250 
    251 WebContents* ChromeWebContentsDelegateAndroid::OpenURLFromTab(
    252     WebContents* source,
    253     const content::OpenURLParams& params) {
    254   WindowOpenDisposition disposition = params.disposition;
    255   if (!source || (disposition != CURRENT_TAB &&
    256                   disposition != NEW_FOREGROUND_TAB &&
    257                   disposition != NEW_BACKGROUND_TAB &&
    258                   disposition != OFF_THE_RECORD &&
    259                   disposition != NEW_POPUP &&
    260                   disposition != NEW_WINDOW)) {
    261     // We can't handle this here.  Give the parent a chance.
    262     return WebContentsDelegateAndroid::OpenURLFromTab(source, params);
    263   }
    264 
    265   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
    266   chrome::NavigateParams nav_params(profile,
    267                                     params.url,
    268                                     params.transition);
    269   FillNavigateParamsFromOpenURLParams(&nav_params, params);
    270   nav_params.source_contents = source;
    271   nav_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
    272   nav_params.user_gesture = params.user_gesture;
    273 
    274   PopupBlockerTabHelper* popup_blocker_helper =
    275       PopupBlockerTabHelper::FromWebContents(source);
    276   DCHECK(popup_blocker_helper);
    277 
    278   if ((params.disposition == NEW_POPUP ||
    279        params.disposition == NEW_FOREGROUND_TAB ||
    280        params.disposition == NEW_BACKGROUND_TAB ||
    281        params.disposition == NEW_WINDOW) &&
    282       !params.user_gesture &&
    283       !CommandLine::ForCurrentProcess()->HasSwitch(
    284           switches::kDisablePopupBlocking)) {
    285     if (popup_blocker_helper->MaybeBlockPopup(nav_params,
    286                                               blink::WebWindowFeatures())) {
    287       return NULL;
    288     }
    289   }
    290 
    291   if (disposition == CURRENT_TAB) {
    292     // Only prerender for a current-tab navigation to avoid session storage
    293     // namespace issues.
    294     nav_params.target_contents = source;
    295     prerender::PrerenderManager* prerender_manager =
    296         prerender::PrerenderManagerFactory::GetForProfile(profile);
    297     if (prerender_manager &&
    298         prerender_manager->MaybeUsePrerenderedPage(params.url, &nav_params)) {
    299       return nav_params.target_contents;
    300     }
    301   }
    302 
    303   return WebContentsDelegateAndroid::OpenURLFromTab(source, params);
    304 }
    305 
    306 void ChromeWebContentsDelegateAndroid::AddNewContents(
    307     WebContents* source,
    308     WebContents* new_contents,
    309     WindowOpenDisposition disposition,
    310     const gfx::Rect& initial_pos,
    311     bool user_gesture,
    312     bool* was_blocked) {
    313   // No code for this yet.
    314   DCHECK_NE(disposition, SAVE_TO_DISK);
    315   // Can't create a new contents for the current tab - invalid case.
    316   DCHECK_NE(disposition, CURRENT_TAB);
    317 
    318   TabHelpers::AttachTabHelpers(new_contents);
    319 
    320   JNIEnv* env = AttachCurrentThread();
    321   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
    322   bool handled = false;
    323   if (!obj.is_null()) {
    324     handled = Java_ChromeWebContentsDelegateAndroid_addNewContents(
    325         env,
    326         obj.obj(),
    327         reinterpret_cast<intptr_t>(source),
    328         reinterpret_cast<intptr_t>(new_contents),
    329         static_cast<jint>(disposition),
    330         NULL,
    331         user_gesture);
    332   }
    333 
    334   if (was_blocked)
    335     *was_blocked = !handled;
    336   if (!handled)
    337     delete new_contents;
    338 }
    339 
    340 void ChromeWebContentsDelegateAndroid::WebContentsCreated(
    341     content::WebContents* source_contents, int opener_render_frame_id,
    342     const base::string16& frame_name, const GURL& target_url,
    343     content::WebContents* new_contents) {
    344   JNIEnv* env = AttachCurrentThread();
    345   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
    346   if (obj.is_null())
    347     return;
    348   Java_ChromeWebContentsDelegateAndroid_webContentsCreated(env, obj.obj(),
    349       reinterpret_cast<intptr_t>(source_contents), opener_render_frame_id,
    350       base::android::ConvertUTF16ToJavaString(env, frame_name).Release(),
    351       base::android::ConvertUTF8ToJavaString(env, target_url.spec()).Release(),
    352       reinterpret_cast<intptr_t>(new_contents));
    353 }
    354 
    355 }  // namespace android
    356 }  // namespace chrome
    357