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