tab_android.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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/tab_android.h" 6 7#include "base/android/jni_android.h" 8#include "base/android/jni_string.h" 9#include "chrome/browser/android/chrome_web_contents_delegate_android.h" 10#include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h" 11#include "chrome/browser/browser_process.h" 12#include "chrome/browser/chrome_notification_types.h" 13#include "chrome/browser/content_settings/tab_specific_content_settings.h" 14#include "chrome/browser/extensions/tab_helper.h" 15#include "chrome/browser/favicon/favicon_tab_helper.h" 16#include "chrome/browser/history/history_tab_helper.h" 17#include "chrome/browser/infobars/infobar_service.h" 18#include "chrome/browser/net/net_error_tab_helper.h" 19#include "chrome/browser/password_manager/password_manager.h" 20#include "chrome/browser/password_manager/password_manager_delegate_impl.h" 21#include "chrome/browser/predictors/resource_prefetch_predictor_factory.h" 22#include "chrome/browser/predictors/resource_prefetch_predictor_tab_helper.h" 23#include "chrome/browser/prerender/prerender_tab_helper.h" 24#include "chrome/browser/profiles/profile.h" 25#include "chrome/browser/profiles/profile_android.h" 26#include "chrome/browser/sessions/session_tab_helper.h" 27#include "chrome/browser/ssl/ssl_tab_helper.h" 28#include "chrome/browser/sync/glue/synced_tab_delegate_android.h" 29#include "chrome/browser/tab_contents/navigation_metrics_recorder.h" 30#include "chrome/browser/translate/translate_tab_helper.h" 31#include "chrome/browser/ui/alternate_error_tab_observer.h" 32#include "chrome/browser/ui/android/infobars/infobar_container_android.h" 33#include "chrome/browser/ui/android/tab_model/tab_model.h" 34#include "chrome/browser/ui/android/tab_model/tab_model_list.h" 35#include "chrome/browser/ui/android/window_android_helper.h" 36#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h" 37#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h" 38#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" 39#include "chrome/browser/ui/browser_tab_contents.h" 40#include "chrome/browser/ui/find_bar/find_tab_helper.h" 41#include "chrome/browser/ui/prefs/prefs_tab_helper.h" 42#include "chrome/browser/ui/tab_contents/core_tab_helper.h" 43#include "chrome/browser/ui/toolbar/toolbar_model_impl.h" 44#include "components/autofill/content/browser/autofill_driver_impl.h" 45#include "content/public/browser/android/content_view_core.h" 46#include "content/public/browser/navigation_entry.h" 47#include "content/public/browser/notification_service.h" 48#include "content/public/browser/web_contents.h" 49#include "extensions/browser/view_type_utils.h" 50#include "jni/TabBase_jni.h" 51 52namespace { 53 54const char kTabHelpersInitializedUserDataKey[] = 55 "TabAndroidTabHelpersInitialized"; 56 57} // namespace 58 59void BrowserTabContents::AttachTabHelpers(content::WebContents* contents) { 60 // If already initialized, nothing to be done. 61 base::SupportsUserData::Data* initialization_tag = 62 contents->GetUserData(&kTabHelpersInitializedUserDataKey); 63 if (initialization_tag) 64 return; 65 66 // Mark as initialized. 67 contents->SetUserData(&kTabHelpersInitializedUserDataKey, 68 new base::SupportsUserData::Data()); 69 70 // Set the view type. 71 extensions::SetViewType(contents, extensions::VIEW_TYPE_TAB_CONTENTS); 72 73 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); 74 75 // SessionTabHelper comes first because it sets up the tab ID, and other 76 // helpers may rely on that. 77 SessionTabHelper::CreateForWebContents(contents); 78 79 AlternateErrorPageTabObserver::CreateForWebContents(contents); 80 autofill::TabAutofillManagerDelegate::CreateForWebContents(contents); 81 autofill::AutofillDriverImpl::CreateForWebContentsAndDelegate( 82 contents, 83 autofill::TabAutofillManagerDelegate::FromWebContents(contents), 84 g_browser_process->GetApplicationLocale(), 85 autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER); 86 BookmarkTabHelper::CreateForWebContents(contents); 87 CoreTabHelper::CreateForWebContents(contents); 88 extensions::TabHelper::CreateForWebContents(contents); 89 FaviconTabHelper::CreateForWebContents(contents); 90 FindTabHelper::CreateForWebContents(contents); 91 HistoryTabHelper::CreateForWebContents(contents); 92 InfoBarService::CreateForWebContents(contents); 93 NavigationMetricsRecorder::CreateForWebContents(contents); 94 chrome_browser_net::NetErrorTabHelper::CreateForWebContents(contents); 95 PasswordManagerDelegateImpl::CreateForWebContents(contents); 96 PasswordManager::CreateForWebContentsAndDelegate( 97 contents, PasswordManagerDelegateImpl::FromWebContents(contents)); 98 PopupBlockerTabHelper::CreateForWebContents(contents); 99 PrefsTabHelper::CreateForWebContents(contents); 100 prerender::PrerenderTabHelper::CreateForWebContentsWithPasswordManager( 101 contents, PasswordManager::FromWebContents(contents)); 102 SingleTabModeTabHelper::CreateForWebContents(contents); 103 SSLTabHelper::CreateForWebContents(contents); 104 TabSpecificContentSettings::CreateForWebContents(contents); 105 TranslateTabHelper::CreateForWebContents(contents); 106 WindowAndroidHelper::CreateForWebContents(contents); 107 108 if (predictors::ResourcePrefetchPredictorFactory::GetForProfile(profile)) { 109 predictors::ResourcePrefetchPredictorTabHelper::CreateForWebContents( 110 contents); 111 } 112} 113 114// TODO(dtrainor): Refactor so we do not need this method. 115void TabAndroid::InitTabHelpers(content::WebContents* contents) { 116 BrowserTabContents::AttachTabHelpers(contents); 117} 118 119TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) { 120 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents); 121 if (!core_tab_helper) 122 return NULL; 123 124 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate(); 125 if (!core_delegate) 126 return NULL; 127 128 return static_cast<TabAndroid*>(core_delegate); 129} 130 131TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) { 132 return reinterpret_cast<TabAndroid*>(Java_TabBase_getNativePtr(env, obj)); 133} 134 135TabAndroid::TabAndroid(JNIEnv* env, jobject obj) 136 : weak_java_tab_(env, obj), 137 session_tab_id_(), 138 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) { 139 Java_TabBase_setNativePtr(env, obj, reinterpret_cast<jint>(this)); 140} 141 142TabAndroid::~TabAndroid() { 143 JNIEnv* env = base::android::AttachCurrentThread(); 144 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 145 if (obj.is_null()) 146 return; 147 148 Java_TabBase_clearNativePtr(env, obj.obj()); 149} 150 151int TabAndroid::GetAndroidId() const { 152 JNIEnv* env = base::android::AttachCurrentThread(); 153 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 154 if (obj.is_null()) 155 return -1; 156 return Java_TabBase_getId(env, obj.obj()); 157} 158 159string16 TabAndroid::GetTitle() const { 160 JNIEnv* env = base::android::AttachCurrentThread(); 161 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 162 if (obj.is_null()) 163 return string16(); 164 return base::android::ConvertJavaStringToUTF16( 165 Java_TabBase_getTitle(env, obj.obj())); 166} 167 168GURL TabAndroid::GetURL() const { 169 JNIEnv* env = base::android::AttachCurrentThread(); 170 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 171 if (obj.is_null()) 172 return GURL::EmptyGURL(); 173 return GURL(base::android::ConvertJavaStringToUTF8( 174 Java_TabBase_getUrl(env, obj.obj()))); 175} 176 177bool TabAndroid::RestoreIfNeeded() { 178 JNIEnv* env = base::android::AttachCurrentThread(); 179 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 180 if (obj.is_null()) 181 return false; 182 return Java_TabBase_restoreIfNeeded(env, obj.obj()); 183} 184 185content::ContentViewCore* TabAndroid::GetContentViewCore() const { 186 if (!web_contents()) 187 return NULL; 188 189 return content::ContentViewCore::FromWebContents(web_contents()); 190} 191 192Profile* TabAndroid::GetProfile() const { 193 if (!web_contents()) 194 return NULL; 195 196 return Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 197} 198 199browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const { 200 return synced_tab_delegate_.get(); 201} 202 203void TabAndroid::SwapTabContents(content::WebContents* old_contents, 204 content::WebContents* new_contents) { 205 JNIEnv* env = base::android::AttachCurrentThread(); 206 207 // We need to notify the native InfobarContainer so infobars can be swapped. 208 InfoBarContainerAndroid* infobar_container = 209 reinterpret_cast<InfoBarContainerAndroid*>( 210 Java_TabBase_getNativeInfoBarContainer( 211 env, 212 weak_java_tab_.get(env).obj())); 213 InfoBarService* new_infobar_service = new_contents ? 214 InfoBarService::FromWebContents(new_contents) : NULL; 215 if (new_infobar_service) 216 infobar_container->ChangeInfoBarService(new_infobar_service); 217 218 Java_TabBase_swapWebContents( 219 env, 220 weak_java_tab_.get(env).obj(), 221 reinterpret_cast<jint>(new_contents)); 222} 223 224void TabAndroid::Observe(int type, 225 const content::NotificationSource& source, 226 const content::NotificationDetails& details) { 227 JNIEnv* env = base::android::AttachCurrentThread(); 228 switch (type) { 229 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: { 230 TabSpecificContentSettings* settings = 231 TabSpecificContentSettings::FromWebContents(web_contents()); 232 if (!settings->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS)) { 233 // TODO(dfalcantara): Create an InfoBarDelegate to keep the 234 // PopupBlockedInfoBar logic native-side instead of straddling the JNI 235 // boundary. 236 int num_popups = 0; 237 PopupBlockerTabHelper* popup_blocker_helper = 238 PopupBlockerTabHelper::FromWebContents(web_contents()); 239 if (popup_blocker_helper) 240 num_popups = popup_blocker_helper->GetBlockedPopupsCount(); 241 242 Java_TabBase_onBlockedPopupsStateChanged(env, 243 weak_java_tab_.get(env).obj(), 244 num_popups); 245 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS); 246 } 247 break; 248 } 249 case chrome::NOTIFICATION_FAVICON_UPDATED: 250 Java_TabBase_onFaviconUpdated(env, weak_java_tab_.get(env).obj()); 251 break; 252 default: 253 NOTREACHED() << "Unexpected notification " << type; 254 break; 255 } 256} 257 258void TabAndroid::InitWebContents(JNIEnv* env, 259 jobject obj, 260 jboolean incognito, 261 jobject jcontent_view_core, 262 jobject jweb_contents_delegate) { 263 content::ContentViewCore* content_view_core = 264 content::ContentViewCore::GetNativeContentViewCore(env, 265 jcontent_view_core); 266 DCHECK(content_view_core); 267 DCHECK(content_view_core->GetWebContents()); 268 269 web_contents_.reset(content_view_core->GetWebContents()); 270 InitTabHelpers(web_contents_.get()); 271 272 session_tab_id_.set_id( 273 SessionTabHelper::FromWebContents(web_contents())->session_id().id()); 274 WindowAndroidHelper::FromWebContents(web_contents())-> 275 SetWindowAndroid(content_view_core->GetWindowAndroid()); 276 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this); 277 web_contents_delegate_.reset( 278 new chrome::android::ChromeWebContentsDelegateAndroid( 279 env, jweb_contents_delegate)); 280 web_contents_delegate_->LoadProgressChanged(web_contents(), 0); 281 web_contents()->SetDelegate(web_contents_delegate_.get()); 282 283 notification_registrar_.Add( 284 this, 285 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 286 content::Source<content::WebContents>(web_contents())); 287 notification_registrar_.Add( 288 this, 289 chrome::NOTIFICATION_FAVICON_UPDATED, 290 content::Source<content::WebContents>(web_contents())); 291 292 synced_tab_delegate_->SetWebContents(web_contents()); 293 294 // Set the window ID if there is a valid TabModel. 295 TabModel* model = TabModelList::GetTabModelWithProfile(GetProfile()); 296 if (model) { 297 SessionID window_id; 298 window_id.set_id(model->GetSessionId()); 299 300 SessionTabHelper* session_tab_helper = 301 SessionTabHelper::FromWebContents(web_contents()); 302 session_tab_helper->SetWindowID(window_id); 303 } 304 305 // Verify that the WebContents this tab represents matches the expected 306 // off the record state. 307 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito); 308} 309 310void TabAndroid::DestroyWebContents(JNIEnv* env, 311 jobject obj, 312 jboolean delete_native) { 313 DCHECK(web_contents()); 314 315 notification_registrar_.Remove( 316 this, 317 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 318 content::Source<content::WebContents>(web_contents())); 319 notification_registrar_.Remove( 320 this, 321 chrome::NOTIFICATION_FAVICON_UPDATED, 322 content::Source<content::WebContents>(web_contents())); 323 324 web_contents()->SetDelegate(NULL); 325 326 if (delete_native) { 327 web_contents_.reset(); 328 synced_tab_delegate_->ResetWebContents(); 329 } else { 330 // Release the WebContents so it does not get deleted by the scoped_ptr. 331 ignore_result(web_contents_.release()); 332 } 333} 334 335base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid( 336 JNIEnv* env, 337 jobject obj) { 338 Profile* profile = GetProfile(); 339 if (!profile) 340 return base::android::ScopedJavaLocalRef<jobject>(); 341 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile); 342 if (!profile_android) 343 return base::android::ScopedJavaLocalRef<jobject>(); 344 345 return profile_android->GetJavaObject(); 346} 347 348void TabAndroid::LaunchBlockedPopups(JNIEnv* env, jobject obj) { 349 PopupBlockerTabHelper* popup_blocker_helper = 350 PopupBlockerTabHelper::FromWebContents(web_contents()); 351 DCHECK(popup_blocker_helper); 352 std::map<int32, GURL> blocked_popups = 353 popup_blocker_helper->GetBlockedPopupRequests(); 354 for (std::map<int32, GURL>::iterator it = blocked_popups.begin(); 355 it != blocked_popups.end(); 356 it++) { 357 popup_blocker_helper->ShowBlockedPopup(it->first); 358 } 359} 360 361ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env, 362 jobject obj) { 363 return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents()); 364} 365 366void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env, 367 jobject obj, 368 jstring jurl, 369 jstring jtitle) { 370 DCHECK(web_contents()); 371 372 string16 title; 373 if (jtitle) 374 title = base::android::ConvertJavaStringToUTF16(env, jtitle); 375 376 std::string url; 377 if (jurl) 378 url = base::android::ConvertJavaStringToUTF8(env, jurl); 379 380 content::NavigationEntry* entry = 381 web_contents()->GetController().GetVisibleEntry(); 382 if (entry && url == entry->GetVirtualURL().spec()) 383 entry->SetTitle(title); 384} 385 386bool TabAndroid::RegisterTabAndroid(JNIEnv* env) { 387 return RegisterNativesImpl(env); 388} 389