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 "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"
54 const char kTabHelpersInitializedUserDataKey[] =
55 "TabAndroidTabHelpersInitialized";
59 void 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)
66 // Mark as initialized.
67 contents->SetUserData(&kTabHelpersInitializedUserDataKey,
68 new base::SupportsUserData::Data());
71 extensions::SetViewType(contents, extensions::VIEW_TYPE_TAB_CONTENTS);
73 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
75 // SessionTabHelper comes first because it sets up the tab ID, and other
76 // helpers may rely on that.
77 SessionTabHelper::CreateForWebContents(contents);
79 AlternateErrorPageTabObserver::CreateForWebContents(contents);
80 autofill::TabAutofillManagerDelegate::CreateForWebContents(contents);
81 autofill::AutofillDriverImpl::CreateForWebContentsAndDelegate(
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);
108 if (predictors::ResourcePrefetchPredictorFactory::GetForProfile(profile)) {
109 predictors::ResourcePrefetchPredictorTabHelper::CreateForWebContents(
114 // TODO(dtrainor): Refactor so we do not need this method.
115 void TabAndroid::InitTabHelpers(content::WebContents* contents) {
116 BrowserTabContents::AttachTabHelpers(contents);
119 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
120 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
121 if (!core_tab_helper)
124 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
128 return static_cast<TabAndroid*>(core_delegate);
131 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
132 return reinterpret_cast<TabAndroid*>(Java_TabBase_getNativePtr(env, obj));
135 TabAndroid::TabAndroid(JNIEnv* env, jobject obj)
136 : weak_java_tab_(env, obj),
138 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
139 Java_TabBase_setNativePtr(env, obj, reinterpret_cast<jint>(this));
142 TabAndroid::~TabAndroid() {
143 JNIEnv* env = base::android::AttachCurrentThread();
144 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
148 Java_TabBase_clearNativePtr(env, obj.obj());
151 int TabAndroid::GetAndroidId() const {
152 JNIEnv* env = base::android::AttachCurrentThread();
153 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
156 return Java_TabBase_getId(env, obj.obj());
159 int TabAndroid::GetSyncId() const {
160 JNIEnv* env = base::android::AttachCurrentThread();
161 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
164 return Java_TabBase_getSyncId(env, obj.obj());
167 string16 TabAndroid::GetTitle() const {
168 JNIEnv* env = base::android::AttachCurrentThread();
169 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
172 return base::android::ConvertJavaStringToUTF16(
173 Java_TabBase_getTitle(env, obj.obj()));
176 GURL TabAndroid::GetURL() const {
177 JNIEnv* env = base::android::AttachCurrentThread();
178 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
180 return GURL::EmptyGURL();
181 return GURL(base::android::ConvertJavaStringToUTF8(
182 Java_TabBase_getUrl(env, obj.obj())));
185 bool TabAndroid::RestoreIfNeeded() {
186 JNIEnv* env = base::android::AttachCurrentThread();
187 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
190 return Java_TabBase_restoreIfNeeded(env, obj.obj());
193 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
197 return content::ContentViewCore::FromWebContents(web_contents());
200 Profile* TabAndroid::GetProfile() const {
204 return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
207 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
208 return synced_tab_delegate_.get();
211 void TabAndroid::SetSyncId(int sync_id) {
212 JNIEnv* env = base::android::AttachCurrentThread();
213 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
216 Java_TabBase_setSyncId(env, obj.obj(), sync_id);
219 void TabAndroid::SwapTabContents(content::WebContents* old_contents,
220 content::WebContents* new_contents) {
221 JNIEnv* env = base::android::AttachCurrentThread();
223 // We need to notify the native InfobarContainer so infobars can be swapped.
224 InfoBarContainerAndroid* infobar_container =
225 reinterpret_cast<InfoBarContainerAndroid*>(
226 Java_TabBase_getNativeInfoBarContainer(
228 weak_java_tab_.get(env).obj()));
229 InfoBarService* new_infobar_service = new_contents ?
230 InfoBarService::FromWebContents(new_contents) : NULL;
231 if (new_infobar_service)
232 infobar_container->ChangeInfoBarService(new_infobar_service);
234 Java_TabBase_swapWebContents(
236 weak_java_tab_.get(env).obj(),
237 reinterpret_cast<jint>(new_contents));
240 void TabAndroid::Observe(int type,
241 const content::NotificationSource& source,
242 const content::NotificationDetails& details) {
243 JNIEnv* env = base::android::AttachCurrentThread();
245 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: {
246 TabSpecificContentSettings* settings =
247 TabSpecificContentSettings::FromWebContents(web_contents());
248 if (!settings->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS)) {
249 // TODO(dfalcantara): Create an InfoBarDelegate to keep the
250 // PopupBlockedInfoBar logic native-side instead of straddling the JNI
253 PopupBlockerTabHelper* popup_blocker_helper =
254 PopupBlockerTabHelper::FromWebContents(web_contents());
255 if (popup_blocker_helper)
256 num_popups = popup_blocker_helper->GetBlockedPopupsCount();
258 Java_TabBase_onBlockedPopupsStateChanged(env,
259 weak_java_tab_.get(env).obj(),
261 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS);
265 case chrome::NOTIFICATION_FAVICON_UPDATED:
266 Java_TabBase_onFaviconUpdated(env, weak_java_tab_.get(env).obj());
269 NOTREACHED() << "Unexpected notification " << type;
274 void TabAndroid::InitWebContents(JNIEnv* env,
277 jobject jcontent_view_core,
278 jobject jweb_contents_delegate) {
279 content::ContentViewCore* content_view_core =
280 content::ContentViewCore::GetNativeContentViewCore(env,
282 DCHECK(content_view_core);
283 DCHECK(content_view_core->GetWebContents());
285 web_contents_.reset(content_view_core->GetWebContents());
286 InitTabHelpers(web_contents_.get());
288 session_tab_id_.set_id(
289 SessionTabHelper::FromWebContents(web_contents())->session_id().id());
290 WindowAndroidHelper::FromWebContents(web_contents())->
291 SetWindowAndroid(content_view_core->GetWindowAndroid());
292 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this);
293 web_contents_delegate_.reset(
294 new chrome::android::ChromeWebContentsDelegateAndroid(
295 env, jweb_contents_delegate));
296 web_contents_delegate_->LoadProgressChanged(web_contents(), 0);
297 web_contents()->SetDelegate(web_contents_delegate_.get());
299 notification_registrar_.Add(
301 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
302 content::Source<content::WebContents>(web_contents()));
303 notification_registrar_.Add(
305 chrome::NOTIFICATION_FAVICON_UPDATED,
306 content::Source<content::WebContents>(web_contents()));
308 synced_tab_delegate_->SetWebContents(web_contents());
310 // Set the window ID if there is a valid TabModel.
311 TabModel* model = TabModelList::GetTabModelWithProfile(GetProfile());
314 window_id.set_id(model->GetSessionId());
316 SessionTabHelper* session_tab_helper =
317 SessionTabHelper::FromWebContents(web_contents());
318 session_tab_helper->SetWindowID(window_id);
321 // Verify that the WebContents this tab represents matches the expected
322 // off the record state.
323 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito);
326 void TabAndroid::DestroyWebContents(JNIEnv* env,
328 jboolean delete_native) {
329 DCHECK(web_contents());
331 notification_registrar_.Remove(
333 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
334 content::Source<content::WebContents>(web_contents()));
335 notification_registrar_.Remove(
337 chrome::NOTIFICATION_FAVICON_UPDATED,
338 content::Source<content::WebContents>(web_contents()));
340 web_contents()->SetDelegate(NULL);
343 web_contents_.reset();
344 synced_tab_delegate_->ResetWebContents();
346 // Release the WebContents so it does not get deleted by the scoped_ptr.
347 ignore_result(web_contents_.release());
351 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid(
354 Profile* profile = GetProfile();
356 return base::android::ScopedJavaLocalRef<jobject>();
357 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
358 if (!profile_android)
359 return base::android::ScopedJavaLocalRef<jobject>();
361 return profile_android->GetJavaObject();
364 void TabAndroid::LaunchBlockedPopups(JNIEnv* env, jobject obj) {
365 PopupBlockerTabHelper* popup_blocker_helper =
366 PopupBlockerTabHelper::FromWebContents(web_contents());
367 DCHECK(popup_blocker_helper);
368 std::map<int32, GURL> blocked_popups =
369 popup_blocker_helper->GetBlockedPopupRequests();
370 for (std::map<int32, GURL>::iterator it = blocked_popups.begin();
371 it != blocked_popups.end();
373 popup_blocker_helper->ShowBlockedPopup(it->first);
377 ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env,
379 return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents());
382 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env,
386 DCHECK(web_contents());
390 title = base::android::ConvertJavaStringToUTF16(env, jtitle);
394 url = base::android::ConvertJavaStringToUTF8(env, jurl);
396 content::NavigationEntry* entry =
397 web_contents()->GetController().GetVisibleEntry();
398 if (entry && url == entry->GetVirtualURL().spec())
399 entry->SetTitle(title);
402 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
403 return RegisterNativesImpl(env);