- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / android / tab_android.cc
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/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"
51
52 namespace {
53
54 const char kTabHelpersInitializedUserDataKey[] =
55     "TabAndroidTabHelpersInitialized";
56
57 }  // namespace
58
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)
64     return;
65
66   // Mark as initialized.
67   contents->SetUserData(&kTabHelpersInitializedUserDataKey,
68                             new base::SupportsUserData::Data());
69
70   // Set the view type.
71   extensions::SetViewType(contents, extensions::VIEW_TYPE_TAB_CONTENTS);
72
73   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
74
75   // SessionTabHelper comes first because it sets up the tab ID, and other
76   // helpers may rely on that.
77   SessionTabHelper::CreateForWebContents(contents);
78
79   AlternateErrorPageTabObserver::CreateForWebContents(contents);
80   autofill::TabAutofillManagerDelegate::CreateForWebContents(contents);
81   autofill::AutofillDriverImpl::CreateForWebContentsAndDelegate(
82       contents,
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);
107
108   if (predictors::ResourcePrefetchPredictorFactory::GetForProfile(profile)) {
109     predictors::ResourcePrefetchPredictorTabHelper::CreateForWebContents(
110         contents);
111   }
112 }
113
114 // TODO(dtrainor): Refactor so we do not need this method.
115 void TabAndroid::InitTabHelpers(content::WebContents* contents) {
116   BrowserTabContents::AttachTabHelpers(contents);
117 }
118
119 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
120   CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
121   if (!core_tab_helper)
122     return NULL;
123
124   CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
125   if (!core_delegate)
126     return NULL;
127
128   return static_cast<TabAndroid*>(core_delegate);
129 }
130
131 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
132   return reinterpret_cast<TabAndroid*>(Java_TabBase_getNativePtr(env, obj));
133 }
134
135 TabAndroid::TabAndroid(JNIEnv* env, jobject obj)
136     : weak_java_tab_(env, obj),
137       session_tab_id_(),
138       synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
139   Java_TabBase_setNativePtr(env, obj, reinterpret_cast<jint>(this));
140 }
141
142 TabAndroid::~TabAndroid() {
143   JNIEnv* env = base::android::AttachCurrentThread();
144   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
145   if (obj.is_null())
146     return;
147
148   Java_TabBase_clearNativePtr(env, obj.obj());
149 }
150
151 int TabAndroid::GetAndroidId() const {
152   JNIEnv* env = base::android::AttachCurrentThread();
153   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
154   if (obj.is_null())
155     return -1;
156   return Java_TabBase_getId(env, obj.obj());
157 }
158
159 int TabAndroid::GetSyncId() const {
160   JNIEnv* env = base::android::AttachCurrentThread();
161   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
162   if (obj.is_null())
163     return 0;
164   return Java_TabBase_getSyncId(env, obj.obj());
165 }
166
167 string16 TabAndroid::GetTitle() const {
168   JNIEnv* env = base::android::AttachCurrentThread();
169   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
170   if (obj.is_null())
171     return string16();
172   return base::android::ConvertJavaStringToUTF16(
173       Java_TabBase_getTitle(env, obj.obj()));
174 }
175
176 GURL TabAndroid::GetURL() const {
177   JNIEnv* env = base::android::AttachCurrentThread();
178   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
179   if (obj.is_null())
180     return GURL::EmptyGURL();
181   return GURL(base::android::ConvertJavaStringToUTF8(
182       Java_TabBase_getUrl(env, obj.obj())));
183 }
184
185 bool TabAndroid::RestoreIfNeeded() {
186   JNIEnv* env = base::android::AttachCurrentThread();
187   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
188   if (obj.is_null())
189     return false;
190   return Java_TabBase_restoreIfNeeded(env, obj.obj());
191 }
192
193 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
194   if (!web_contents())
195     return NULL;
196
197   return content::ContentViewCore::FromWebContents(web_contents());
198 }
199
200 Profile* TabAndroid::GetProfile() const {
201   if (!web_contents())
202     return NULL;
203
204   return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
205 }
206
207 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
208   return synced_tab_delegate_.get();
209 }
210
211 void TabAndroid::SetSyncId(int sync_id) {
212   JNIEnv* env = base::android::AttachCurrentThread();
213   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
214   if (obj.is_null())
215     return;
216   Java_TabBase_setSyncId(env, obj.obj(), sync_id);
217 }
218
219 void TabAndroid::SwapTabContents(content::WebContents* old_contents,
220                                  content::WebContents* new_contents) {
221   JNIEnv* env = base::android::AttachCurrentThread();
222
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(
227               env,
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);
233
234   Java_TabBase_swapWebContents(
235       env,
236       weak_java_tab_.get(env).obj(),
237       reinterpret_cast<jint>(new_contents));
238 }
239
240 void TabAndroid::Observe(int type,
241                          const content::NotificationSource& source,
242                          const content::NotificationDetails& details) {
243   JNIEnv* env = base::android::AttachCurrentThread();
244   switch (type) {
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
251         // boundary.
252         int num_popups = 0;
253         PopupBlockerTabHelper* popup_blocker_helper =
254             PopupBlockerTabHelper::FromWebContents(web_contents());
255         if (popup_blocker_helper)
256           num_popups = popup_blocker_helper->GetBlockedPopupsCount();
257
258         Java_TabBase_onBlockedPopupsStateChanged(env,
259                                                  weak_java_tab_.get(env).obj(),
260                                                  num_popups);
261         settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS);
262       }
263       break;
264     }
265     case chrome::NOTIFICATION_FAVICON_UPDATED:
266       Java_TabBase_onFaviconUpdated(env, weak_java_tab_.get(env).obj());
267       break;
268     default:
269       NOTREACHED() << "Unexpected notification " << type;
270       break;
271   }
272 }
273
274 void TabAndroid::InitWebContents(JNIEnv* env,
275                                  jobject obj,
276                                  jboolean incognito,
277                                  jobject jcontent_view_core,
278                                  jobject jweb_contents_delegate) {
279   content::ContentViewCore* content_view_core =
280       content::ContentViewCore::GetNativeContentViewCore(env,
281                                                          jcontent_view_core);
282   DCHECK(content_view_core);
283   DCHECK(content_view_core->GetWebContents());
284
285   web_contents_.reset(content_view_core->GetWebContents());
286   InitTabHelpers(web_contents_.get());
287
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());
298
299   notification_registrar_.Add(
300       this,
301       chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
302       content::Source<content::WebContents>(web_contents()));
303   notification_registrar_.Add(
304       this,
305       chrome::NOTIFICATION_FAVICON_UPDATED,
306       content::Source<content::WebContents>(web_contents()));
307
308   synced_tab_delegate_->SetWebContents(web_contents());
309
310   // Set the window ID if there is a valid TabModel.
311   TabModel* model = TabModelList::GetTabModelWithProfile(GetProfile());
312   if (model) {
313     SessionID window_id;
314     window_id.set_id(model->GetSessionId());
315
316     SessionTabHelper* session_tab_helper =
317         SessionTabHelper::FromWebContents(web_contents());
318     session_tab_helper->SetWindowID(window_id);
319   }
320
321   // Verify that the WebContents this tab represents matches the expected
322   // off the record state.
323   CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito);
324 }
325
326 void TabAndroid::DestroyWebContents(JNIEnv* env,
327                                     jobject obj,
328                                     jboolean delete_native) {
329   DCHECK(web_contents());
330
331   notification_registrar_.Remove(
332       this,
333       chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
334       content::Source<content::WebContents>(web_contents()));
335   notification_registrar_.Remove(
336       this,
337       chrome::NOTIFICATION_FAVICON_UPDATED,
338       content::Source<content::WebContents>(web_contents()));
339
340   web_contents()->SetDelegate(NULL);
341
342   if (delete_native) {
343     web_contents_.reset();
344     synced_tab_delegate_->ResetWebContents();
345   } else {
346     // Release the WebContents so it does not get deleted by the scoped_ptr.
347     ignore_result(web_contents_.release());
348   }
349 }
350
351 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid(
352     JNIEnv* env,
353     jobject obj) {
354   Profile* profile = GetProfile();
355   if (!profile)
356     return base::android::ScopedJavaLocalRef<jobject>();
357   ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
358   if (!profile_android)
359     return base::android::ScopedJavaLocalRef<jobject>();
360
361   return profile_android->GetJavaObject();
362 }
363
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();
372       it++) {
373     popup_blocker_helper->ShowBlockedPopup(it->first);
374   }
375 }
376
377 ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env,
378                                                          jobject obj) {
379   return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents());
380 }
381
382 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env,
383                                                      jobject obj,
384                                                      jstring jurl,
385                                                      jstring jtitle) {
386   DCHECK(web_contents());
387
388   string16 title;
389   if (jtitle)
390     title = base::android::ConvertJavaStringToUTF16(env, jtitle);
391
392   std::string url;
393   if (jurl)
394     url = base::android::ConvertJavaStringToUTF8(env, jurl);
395
396   content::NavigationEntry* entry =
397       web_contents()->GetController().GetVisibleEntry();
398   if (entry && url == entry->GetVirtualURL().spec())
399     entry->SetTitle(title);
400 }
401
402 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
403   return RegisterNativesImpl(env);
404 }