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 41using base::android::AttachCurrentThread; 42using base::android::ScopedJavaLocalRef; 43using content::FileChooserParams; 44using content::WebContents; 45 46namespace { 47 48ScopedJavaLocalRef<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 59ScopedJavaLocalRef<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 73namespace chrome { 74namespace android { 75 76ChromeWebContentsDelegateAndroid::ChromeWebContentsDelegateAndroid(JNIEnv* env, 77 jobject obj) 78 : WebContentsDelegateAndroid(env, obj) { 79} 80 81ChromeWebContentsDelegateAndroid::~ChromeWebContentsDelegateAndroid() { 82 notification_registrar_.RemoveAll(); 83} 84 85// Register native methods. 86bool RegisterChromeWebContentsDelegateAndroid(JNIEnv* env) { 87 return RegisterNativesImpl(env); 88} 89 90void 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 98void ChromeWebContentsDelegateAndroid::RunFileChooser( 99 WebContents* web_contents, 100 const FileChooserParams& params) { 101 FileSelectHelper::RunFileChooser(web_contents, params); 102} 103 104void 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 118void 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 134void 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 157void 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 183void 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 216content::JavaScriptDialogManager* 217ChromeWebContentsDelegateAndroid::GetJavaScriptDialogManager() { 218 return GetJavaScriptDialogManagerInstance(); 219} 220 221void 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 229bool 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 237bool 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 251WebContents* 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 306void 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 340void 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