tab_android.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "base/debug/trace_event.h" 10#include "chrome/browser/android/chrome_web_contents_delegate_android.h" 11#include "chrome/browser/chrome_notification_types.h" 12#include "chrome/browser/content_settings/tab_specific_content_settings.h" 13#include "chrome/browser/printing/print_view_manager_basic.h" 14#include "chrome/browser/profiles/profile.h" 15#include "chrome/browser/profiles/profile_android.h" 16#include "chrome/browser/sessions/session_tab_helper.h" 17#include "chrome/browser/sync/glue/synced_tab_delegate_android.h" 18#include "chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h" 19#include "chrome/browser/ui/android/context_menu_helper.h" 20#include "chrome/browser/ui/android/infobars/infobar_container_android.h" 21#include "chrome/browser/ui/android/tab_model/tab_model.h" 22#include "chrome/browser/ui/android/tab_model/tab_model_list.h" 23#include "chrome/browser/ui/android/window_android_helper.h" 24#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h" 25#include "chrome/browser/ui/tab_contents/core_tab_helper.h" 26#include "chrome/browser/ui/tab_helpers.h" 27#include "chrome/browser/ui/toolbar/toolbar_model_impl.h" 28#include "content/public/browser/android/content_view_core.h" 29#include "content/public/browser/navigation_entry.h" 30#include "content/public/browser/notification_service.h" 31#include "content/public/browser/web_contents.h" 32#include "jni/TabBase_jni.h" 33 34TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) { 35 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents); 36 if (!core_tab_helper) 37 return NULL; 38 39 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate(); 40 if (!core_delegate) 41 return NULL; 42 43 return static_cast<TabAndroid*>(core_delegate); 44} 45 46TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) { 47 return reinterpret_cast<TabAndroid*>(Java_TabBase_getNativePtr(env, obj)); 48} 49 50TabAndroid::TabAndroid(JNIEnv* env, jobject obj) 51 : weak_java_tab_(env, obj), 52 session_tab_id_(), 53 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) { 54 Java_TabBase_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this)); 55} 56 57TabAndroid::~TabAndroid() { 58 JNIEnv* env = base::android::AttachCurrentThread(); 59 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 60 if (obj.is_null()) 61 return; 62 63 Java_TabBase_clearNativePtr(env, obj.obj()); 64} 65 66base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() { 67 JNIEnv* env = base::android::AttachCurrentThread(); 68 return weak_java_tab_.get(env); 69} 70 71int TabAndroid::GetAndroidId() const { 72 JNIEnv* env = base::android::AttachCurrentThread(); 73 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 74 if (obj.is_null()) 75 return -1; 76 return Java_TabBase_getId(env, obj.obj()); 77} 78 79int TabAndroid::GetSyncId() const { 80 JNIEnv* env = base::android::AttachCurrentThread(); 81 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 82 if (obj.is_null()) 83 return 0; 84 return Java_TabBase_getSyncId(env, obj.obj()); 85} 86 87base::string16 TabAndroid::GetTitle() const { 88 JNIEnv* env = base::android::AttachCurrentThread(); 89 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 90 if (obj.is_null()) 91 return base::string16(); 92 return base::android::ConvertJavaStringToUTF16( 93 Java_TabBase_getTitle(env, obj.obj())); 94} 95 96GURL TabAndroid::GetURL() const { 97 JNIEnv* env = base::android::AttachCurrentThread(); 98 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 99 if (obj.is_null()) 100 return GURL::EmptyGURL(); 101 return GURL(base::android::ConvertJavaStringToUTF8( 102 Java_TabBase_getUrl(env, obj.obj()))); 103} 104 105bool TabAndroid::RestoreIfNeeded() { 106 JNIEnv* env = base::android::AttachCurrentThread(); 107 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 108 if (obj.is_null()) 109 return false; 110 return Java_TabBase_restoreIfNeeded(env, obj.obj()); 111} 112 113content::ContentViewCore* TabAndroid::GetContentViewCore() const { 114 if (!web_contents()) 115 return NULL; 116 117 return content::ContentViewCore::FromWebContents(web_contents()); 118} 119 120Profile* TabAndroid::GetProfile() const { 121 if (!web_contents()) 122 return NULL; 123 124 return Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 125} 126 127browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const { 128 return synced_tab_delegate_.get(); 129} 130 131void TabAndroid::SetSyncId(int sync_id) { 132 JNIEnv* env = base::android::AttachCurrentThread(); 133 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env); 134 if (obj.is_null()) 135 return; 136 Java_TabBase_setSyncId(env, obj.obj(), sync_id); 137} 138 139void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) { 140 NOTIMPLEMENTED(); 141} 142 143void TabAndroid::OnReceivedHttpAuthRequest(jobject auth_handler, 144 const base::string16& host, 145 const base::string16& realm) { 146 NOTIMPLEMENTED(); 147} 148 149void TabAndroid::AddShortcutToBookmark(const GURL& url, 150 const base::string16& title, 151 const SkBitmap& skbitmap, 152 int r_value, 153 int g_value, 154 int b_value) { 155 NOTREACHED(); 156} 157 158void TabAndroid::EditBookmark(int64 node_id, 159 const base::string16& node_title, 160 bool is_folder, 161 bool is_partner_bookmark) { 162 NOTREACHED(); 163} 164 165void TabAndroid::OnNewTabPageReady() { 166 NOTREACHED(); 167} 168 169bool TabAndroid::ShouldWelcomePageLinkToTermsOfService() { 170 NOTIMPLEMENTED(); 171 return false; 172} 173 174void TabAndroid::SwapTabContents(content::WebContents* old_contents, 175 content::WebContents* new_contents, 176 bool did_start_load, 177 bool did_finish_load) { 178 JNIEnv* env = base::android::AttachCurrentThread(); 179 180 // We need to notify the native InfobarContainer so infobars can be swapped. 181 InfoBarContainerAndroid* infobar_container = 182 reinterpret_cast<InfoBarContainerAndroid*>( 183 Java_TabBase_getNativeInfoBarContainer( 184 env, 185 weak_java_tab_.get(env).obj())); 186 InfoBarService* new_infobar_service = new_contents ? 187 InfoBarService::FromWebContents(new_contents) : NULL; 188 infobar_container->ChangeInfoBarService(new_infobar_service); 189 190 Java_TabBase_swapWebContents( 191 env, 192 weak_java_tab_.get(env).obj(), 193 reinterpret_cast<intptr_t>(new_contents), 194 did_start_load, 195 did_finish_load); 196} 197 198void TabAndroid::Observe(int type, 199 const content::NotificationSource& source, 200 const content::NotificationDetails& details) { 201 JNIEnv* env = base::android::AttachCurrentThread(); 202 switch (type) { 203 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: { 204 TabSpecificContentSettings* settings = 205 TabSpecificContentSettings::FromWebContents(web_contents()); 206 if (!settings->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS)) { 207 // TODO(dfalcantara): Create an InfoBarDelegate to keep the 208 // PopupBlockedInfoBar logic native-side instead of straddling the JNI 209 // boundary. 210 int num_popups = 0; 211 PopupBlockerTabHelper* popup_blocker_helper = 212 PopupBlockerTabHelper::FromWebContents(web_contents()); 213 if (popup_blocker_helper) 214 num_popups = popup_blocker_helper->GetBlockedPopupsCount(); 215 216 if (num_popups > 0) 217 PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups); 218 219 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS); 220 } 221 break; 222 } 223 case chrome::NOTIFICATION_FAVICON_UPDATED: 224 Java_TabBase_onFaviconUpdated(env, weak_java_tab_.get(env).obj()); 225 break; 226 case content::NOTIFICATION_NAV_ENTRY_CHANGED: 227 Java_TabBase_onNavEntryChanged(env, weak_java_tab_.get(env).obj()); 228 break; 229 default: 230 NOTREACHED() << "Unexpected notification " << type; 231 break; 232 } 233} 234 235void TabAndroid::Destroy(JNIEnv* env, jobject obj) { 236 delete this; 237} 238 239void TabAndroid::InitWebContents(JNIEnv* env, 240 jobject obj, 241 jboolean incognito, 242 jobject jcontent_view_core, 243 jobject jweb_contents_delegate, 244 jobject jcontext_menu_populator) { 245 content::ContentViewCore* content_view_core = 246 content::ContentViewCore::GetNativeContentViewCore(env, 247 jcontent_view_core); 248 DCHECK(content_view_core); 249 DCHECK(content_view_core->GetWebContents()); 250 251 web_contents_.reset(content_view_core->GetWebContents()); 252 TabHelpers::AttachTabHelpers(web_contents_.get()); 253 254 session_tab_id_.set_id( 255 SessionTabHelper::FromWebContents(web_contents())->session_id().id()); 256 ContextMenuHelper::FromWebContents(web_contents())->SetPopulator( 257 jcontext_menu_populator); 258 WindowAndroidHelper::FromWebContents(web_contents())-> 259 SetWindowAndroid(content_view_core->GetWindowAndroid()); 260 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this); 261 web_contents_delegate_.reset( 262 new chrome::android::ChromeWebContentsDelegateAndroid( 263 env, jweb_contents_delegate)); 264 web_contents_delegate_->LoadProgressChanged(web_contents(), 0); 265 web_contents()->SetDelegate(web_contents_delegate_.get()); 266 267 notification_registrar_.Add( 268 this, 269 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 270 content::Source<content::WebContents>(web_contents())); 271 notification_registrar_.Add( 272 this, 273 chrome::NOTIFICATION_FAVICON_UPDATED, 274 content::Source<content::WebContents>(web_contents())); 275 notification_registrar_.Add( 276 this, 277 content::NOTIFICATION_NAV_ENTRY_CHANGED, 278 content::Source<content::NavigationController>( 279 &web_contents()->GetController())); 280 281 synced_tab_delegate_->SetWebContents(web_contents()); 282 283 // Set the window ID if there is a valid TabModel. 284 TabModel* model = TabModelList::GetTabModelWithProfile(GetProfile()); 285 if (model) { 286 SessionID window_id; 287 window_id.set_id(model->GetSessionId()); 288 289 SessionTabHelper* session_tab_helper = 290 SessionTabHelper::FromWebContents(web_contents()); 291 session_tab_helper->SetWindowID(window_id); 292 } 293 294 // Verify that the WebContents this tab represents matches the expected 295 // off the record state. 296 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito); 297} 298 299void TabAndroid::DestroyWebContents(JNIEnv* env, 300 jobject obj, 301 jboolean delete_native) { 302 DCHECK(web_contents()); 303 304 notification_registrar_.Remove( 305 this, 306 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 307 content::Source<content::WebContents>(web_contents())); 308 notification_registrar_.Remove( 309 this, 310 chrome::NOTIFICATION_FAVICON_UPDATED, 311 content::Source<content::WebContents>(web_contents())); 312 313 web_contents()->SetDelegate(NULL); 314 315 if (delete_native) { 316 web_contents_.reset(); 317 synced_tab_delegate_->ResetWebContents(); 318 } else { 319 // Release the WebContents so it does not get deleted by the scoped_ptr. 320 ignore_result(web_contents_.release()); 321 } 322} 323 324base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetWebContents( 325 JNIEnv* env, 326 jobject obj) { 327 if (!web_contents_.get()) 328 return base::android::ScopedJavaLocalRef<jobject>(); 329 return web_contents_->GetJavaWebContents(); 330} 331 332base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid( 333 JNIEnv* env, 334 jobject obj) { 335 Profile* profile = GetProfile(); 336 if (!profile) 337 return base::android::ScopedJavaLocalRef<jobject>(); 338 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile); 339 if (!profile_android) 340 return base::android::ScopedJavaLocalRef<jobject>(); 341 342 return profile_android->GetJavaObject(); 343} 344 345ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env, 346 jobject obj) { 347 return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents()); 348} 349 350void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env, 351 jobject obj, 352 jstring jurl, 353 jstring jtitle) { 354 DCHECK(web_contents()); 355 356 base::string16 title; 357 if (jtitle) 358 title = base::android::ConvertJavaStringToUTF16(env, jtitle); 359 360 std::string url; 361 if (jurl) 362 url = base::android::ConvertJavaStringToUTF8(env, jurl); 363 364 content::NavigationEntry* entry = 365 web_contents()->GetController().GetVisibleEntry(); 366 if (entry && url == entry->GetVirtualURL().spec()) 367 entry->SetTitle(title); 368} 369 370bool TabAndroid::Print(JNIEnv* env, jobject obj) { 371 if (!web_contents()) 372 return false; 373 374 printing::PrintViewManagerBasic::CreateForWebContents(web_contents()); 375 printing::PrintViewManagerBasic* print_view_manager = 376 printing::PrintViewManagerBasic::FromWebContents(web_contents()); 377 if (print_view_manager == NULL) 378 return false; 379 380 print_view_manager->PrintNow(); 381 return true; 382} 383 384static void Init(JNIEnv* env, jobject obj) { 385 TRACE_EVENT0("native", "TabAndroid::Init"); 386 // This will automatically bind to the Java object and pass ownership there. 387 new TabAndroid(env, obj); 388} 389 390bool TabAndroid::RegisterTabAndroid(JNIEnv* env) { 391 return RegisterNativesImpl(env); 392} 393