Home | History | Annotate | Download | only in android
      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 
     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.
    128 void TabAndroid::InitTabHelpers(content::WebContents* contents) {
    129   BrowserTabContents::AttachTabHelpers(contents);
    130 }
    131 
    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 
    144 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
    145   return reinterpret_cast<TabAndroid*>(Java_TabBase_getNativePtr(env, obj));
    146 }
    147 
    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 
    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 
    164 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 
    172 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 
    180 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 
    189 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 
    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 
    206 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
    207   if (!web_contents())
    208     return NULL;
    209 
    210   return content::ContentViewCore::FromWebContents(web_contents());
    211 }
    212 
    213 Profile* TabAndroid::GetProfile() const {
    214   if (!web_contents())
    215     return NULL;
    216 
    217   return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
    218 }
    219 
    220 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
    221   return synced_tab_delegate_.get();
    222 }
    223 
    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 
    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 
    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 
    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 
    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 
    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 
    382 ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env,
    383                                                          jobject obj) {
    384   return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents());
    385 }
    386 
    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 
    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 
    421 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
    422   return RegisterNativesImpl(env);
    423 }
    424