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::RequestPpapiBrokerPermission(
    230     WebContents* web_contents,
    231     const GURL& url,
    232     const base::FilePath& plugin_path,
    233     const base::Callback<void(bool)>& callback) {
    234 #if defined(ENABLE_PLUGINS)
    235     PepperBrokerInfoBarDelegate::Create(
    236         web_contents, url, plugin_path, callback);
    237     return true;
    238 #else
    239     return false;
    240 #endif
    241 }
    242 
    243 WebContents* ChromeWebContentsDelegateAndroid::OpenURLFromTab(
    244     WebContents* source,
    245     const content::OpenURLParams& params) {
    246   WindowOpenDisposition disposition = params.disposition;
    247   if (!source || (disposition != CURRENT_TAB &&
    248                   disposition != NEW_FOREGROUND_TAB &&
    249                   disposition != NEW_BACKGROUND_TAB &&
    250                   disposition != OFF_THE_RECORD &&
    251                   disposition != NEW_POPUP &&
    252                   disposition != NEW_WINDOW)) {
    253     // We can't handle this here.  Give the parent a chance.
    254     return WebContentsDelegateAndroid::OpenURLFromTab(source, params);
    255   }
    256 
    257   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
    258   chrome::NavigateParams nav_params(profile,
    259                                     params.url,
    260                                     params.transition);
    261   FillNavigateParamsFromOpenURLParams(&nav_params, params);
    262   nav_params.source_contents = source;
    263   nav_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
    264   nav_params.user_gesture = params.user_gesture;
    265 
    266   PopupBlockerTabHelper* popup_blocker_helper =
    267       PopupBlockerTabHelper::FromWebContents(source);
    268   DCHECK(popup_blocker_helper);
    269 
    270   if ((params.disposition == NEW_POPUP ||
    271        params.disposition == NEW_FOREGROUND_TAB ||
    272        params.disposition == NEW_BACKGROUND_TAB ||
    273        params.disposition == NEW_WINDOW) &&
    274       !params.user_gesture &&
    275       !CommandLine::ForCurrentProcess()->HasSwitch(
    276           switches::kDisablePopupBlocking)) {
    277     if (popup_blocker_helper->MaybeBlockPopup(nav_params,
    278                                               blink::WebWindowFeatures())) {
    279       return NULL;
    280     }
    281   }
    282 
    283   if (disposition == CURRENT_TAB) {
    284     // Only prerender for a current-tab navigation to avoid session storage
    285     // namespace issues.
    286     nav_params.target_contents = source;
    287     prerender::PrerenderManager* prerender_manager =
    288         prerender::PrerenderManagerFactory::GetForProfile(profile);
    289     if (prerender_manager &&
    290         prerender_manager->MaybeUsePrerenderedPage(params.url, &nav_params)) {
    291       return nav_params.target_contents;
    292     }
    293   }
    294 
    295   return WebContentsDelegateAndroid::OpenURLFromTab(source, params);
    296 }
    297 
    298 void ChromeWebContentsDelegateAndroid::AddNewContents(
    299     WebContents* source,
    300     WebContents* new_contents,
    301     WindowOpenDisposition disposition,
    302     const gfx::Rect& initial_pos,
    303     bool user_gesture,
    304     bool* was_blocked) {
    305   // No code for this yet.
    306   DCHECK_NE(disposition, SAVE_TO_DISK);
    307   // Can't create a new contents for the current tab - invalid case.
    308   DCHECK_NE(disposition, CURRENT_TAB);
    309 
    310   TabHelpers::AttachTabHelpers(new_contents);
    311 
    312   JNIEnv* env = AttachCurrentThread();
    313   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
    314   bool handled = false;
    315   if (!obj.is_null()) {
    316     handled = Java_ChromeWebContentsDelegateAndroid_addNewContents(
    317         env,
    318         obj.obj(),
    319         reinterpret_cast<intptr_t>(source),
    320         reinterpret_cast<intptr_t>(new_contents),
    321         static_cast<jint>(disposition),
    322         NULL,
    323         user_gesture);
    324   }
    325 
    326   if (!handled)
    327     delete new_contents;
    328 }
    329 
    330 void ChromeWebContentsDelegateAndroid::WebContentsCreated(
    331     content::WebContents* source_contents, int opener_render_frame_id,
    332     const base::string16& frame_name, const GURL& target_url,
    333     content::WebContents* new_contents) {
    334   JNIEnv* env = AttachCurrentThread();
    335   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
    336   if (obj.is_null())
    337     return;
    338   Java_ChromeWebContentsDelegateAndroid_webContentsCreated(env, obj.obj(),
    339       reinterpret_cast<intptr_t>(source_contents), opener_render_frame_id,
    340       base::android::ConvertUTF16ToJavaString(env, frame_name).Release(),
    341       base::android::ConvertUTF8ToJavaString(env, target_url.spec()).Release(),
    342       reinterpret_cast<intptr_t>(new_contents));
    343 }
    344 
    345 }  // namespace android
    346 }  // namespace chrome
    347