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.
5 #include "chrome/browser/android/tab_android.h"
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"
34 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
35 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
39 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
43 return static_cast<TabAndroid*>(core_delegate);
46 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
47 return reinterpret_cast<TabAndroid*>(Java_TabBase_getNativePtr(env, obj));
50 TabAndroid::TabAndroid(JNIEnv* env, jobject obj)
51 : weak_java_tab_(env, obj),
53 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
54 Java_TabBase_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this));
57 TabAndroid::~TabAndroid() {
58 JNIEnv* env = base::android::AttachCurrentThread();
59 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
63 Java_TabBase_clearNativePtr(env, obj.obj());
66 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() {
67 JNIEnv* env = base::android::AttachCurrentThread();
68 return weak_java_tab_.get(env);
71 int TabAndroid::GetAndroidId() const {
72 JNIEnv* env = base::android::AttachCurrentThread();
73 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
76 return Java_TabBase_getId(env, obj.obj());
79 int TabAndroid::GetSyncId() const {
80 JNIEnv* env = base::android::AttachCurrentThread();
81 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
84 return Java_TabBase_getSyncId(env, obj.obj());
87 base::string16 TabAndroid::GetTitle() const {
88 JNIEnv* env = base::android::AttachCurrentThread();
89 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
91 return base::string16();
92 return base::android::ConvertJavaStringToUTF16(
93 Java_TabBase_getTitle(env, obj.obj()));
96 GURL TabAndroid::GetURL() const {
97 JNIEnv* env = base::android::AttachCurrentThread();
98 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
100 return GURL::EmptyGURL();
101 return GURL(base::android::ConvertJavaStringToUTF8(
102 Java_TabBase_getUrl(env, obj.obj())));
105 bool TabAndroid::RestoreIfNeeded() {
106 JNIEnv* env = base::android::AttachCurrentThread();
107 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
110 return Java_TabBase_restoreIfNeeded(env, obj.obj());
113 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
117 return content::ContentViewCore::FromWebContents(web_contents());
120 Profile* TabAndroid::GetProfile() const {
124 return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
127 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
128 return synced_tab_delegate_.get();
131 void TabAndroid::SetSyncId(int sync_id) {
132 JNIEnv* env = base::android::AttachCurrentThread();
133 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
136 Java_TabBase_setSyncId(env, obj.obj(), sync_id);
139 void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) {
143 void TabAndroid::OnReceivedHttpAuthRequest(jobject auth_handler,
144 const base::string16& host,
145 const base::string16& realm) {
149 void TabAndroid::AddShortcutToBookmark(const GURL& url,
150 const base::string16& title,
151 const SkBitmap& skbitmap,
158 void TabAndroid::EditBookmark(int64 node_id,
159 const base::string16& node_title,
161 bool is_partner_bookmark) {
165 void TabAndroid::OnNewTabPageReady() {
169 bool TabAndroid::ShouldWelcomePageLinkToTermsOfService() {
174 void TabAndroid::SwapTabContents(content::WebContents* old_contents,
175 content::WebContents* new_contents,
177 bool did_finish_load) {
178 JNIEnv* env = base::android::AttachCurrentThread();
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(
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);
190 Java_TabBase_swapWebContents(
192 weak_java_tab_.get(env).obj(),
193 reinterpret_cast<intptr_t>(new_contents),
198 void TabAndroid::Observe(int type,
199 const content::NotificationSource& source,
200 const content::NotificationDetails& details) {
201 JNIEnv* env = base::android::AttachCurrentThread();
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
211 PopupBlockerTabHelper* popup_blocker_helper =
212 PopupBlockerTabHelper::FromWebContents(web_contents());
213 if (popup_blocker_helper)
214 num_popups = popup_blocker_helper->GetBlockedPopupsCount();
217 PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups);
219 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS);
223 case chrome::NOTIFICATION_FAVICON_UPDATED:
224 Java_TabBase_onFaviconUpdated(env, weak_java_tab_.get(env).obj());
226 case content::NOTIFICATION_NAV_ENTRY_CHANGED:
227 Java_TabBase_onNavEntryChanged(env, weak_java_tab_.get(env).obj());
230 NOTREACHED() << "Unexpected notification " << type;
235 void TabAndroid::Destroy(JNIEnv* env, jobject obj) {
239 void TabAndroid::InitWebContents(JNIEnv* env,
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,
248 DCHECK(content_view_core);
249 DCHECK(content_view_core->GetWebContents());
251 web_contents_.reset(content_view_core->GetWebContents());
252 TabHelpers::AttachTabHelpers(web_contents_.get());
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());
267 notification_registrar_.Add(
269 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
270 content::Source<content::WebContents>(web_contents()));
271 notification_registrar_.Add(
273 chrome::NOTIFICATION_FAVICON_UPDATED,
274 content::Source<content::WebContents>(web_contents()));
275 notification_registrar_.Add(
277 content::NOTIFICATION_NAV_ENTRY_CHANGED,
278 content::Source<content::NavigationController>(
279 &web_contents()->GetController()));
281 synced_tab_delegate_->SetWebContents(web_contents());
283 // Set the window ID if there is a valid TabModel.
284 TabModel* model = TabModelList::GetTabModelWithProfile(GetProfile());
287 window_id.set_id(model->GetSessionId());
289 SessionTabHelper* session_tab_helper =
290 SessionTabHelper::FromWebContents(web_contents());
291 session_tab_helper->SetWindowID(window_id);
294 // Verify that the WebContents this tab represents matches the expected
295 // off the record state.
296 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito);
299 void TabAndroid::DestroyWebContents(JNIEnv* env,
301 jboolean delete_native) {
302 DCHECK(web_contents());
304 notification_registrar_.Remove(
306 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
307 content::Source<content::WebContents>(web_contents()));
308 notification_registrar_.Remove(
310 chrome::NOTIFICATION_FAVICON_UPDATED,
311 content::Source<content::WebContents>(web_contents()));
313 web_contents()->SetDelegate(NULL);
316 web_contents_.reset();
317 synced_tab_delegate_->ResetWebContents();
319 // Release the WebContents so it does not get deleted by the scoped_ptr.
320 ignore_result(web_contents_.release());
324 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetWebContents(
327 if (!web_contents_.get())
328 return base::android::ScopedJavaLocalRef<jobject>();
329 return web_contents_->GetJavaWebContents();
332 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid(
335 Profile* profile = GetProfile();
337 return base::android::ScopedJavaLocalRef<jobject>();
338 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
339 if (!profile_android)
340 return base::android::ScopedJavaLocalRef<jobject>();
342 return profile_android->GetJavaObject();
345 ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env,
347 return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents());
350 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env,
354 DCHECK(web_contents());
356 base::string16 title;
358 title = base::android::ConvertJavaStringToUTF16(env, jtitle);
362 url = base::android::ConvertJavaStringToUTF8(env, jurl);
364 content::NavigationEntry* entry =
365 web_contents()->GetController().GetVisibleEntry();
366 if (entry && url == entry->GetVirtualURL().spec())
367 entry->SetTitle(title);
370 bool TabAndroid::Print(JNIEnv* env, jobject obj) {
374 printing::PrintViewManagerBasic::CreateForWebContents(web_contents());
375 printing::PrintViewManagerBasic* print_view_manager =
376 printing::PrintViewManagerBasic::FromWebContents(web_contents());
377 if (print_view_manager == NULL)
380 print_view_manager->PrintNow();
384 static 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);
390 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
391 return RegisterNativesImpl(env);