Upstream version 5.34.104.0
[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 "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"
33
34 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
35   CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
36   if (!core_tab_helper)
37     return NULL;
38
39   CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
40   if (!core_delegate)
41     return NULL;
42
43   return static_cast<TabAndroid*>(core_delegate);
44 }
45
46 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
47   return reinterpret_cast<TabAndroid*>(Java_TabBase_getNativePtr(env, obj));
48 }
49
50 TabAndroid::TabAndroid(JNIEnv* env, jobject obj)
51     : weak_java_tab_(env, obj),
52       session_tab_id_(),
53       synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
54   Java_TabBase_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this));
55 }
56
57 TabAndroid::~TabAndroid() {
58   JNIEnv* env = base::android::AttachCurrentThread();
59   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
60   if (obj.is_null())
61     return;
62
63   Java_TabBase_clearNativePtr(env, obj.obj());
64 }
65
66 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() {
67   JNIEnv* env = base::android::AttachCurrentThread();
68   return weak_java_tab_.get(env);
69 }
70
71 int TabAndroid::GetAndroidId() const {
72   JNIEnv* env = base::android::AttachCurrentThread();
73   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
74   if (obj.is_null())
75     return -1;
76   return Java_TabBase_getId(env, obj.obj());
77 }
78
79 int TabAndroid::GetSyncId() const {
80   JNIEnv* env = base::android::AttachCurrentThread();
81   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
82   if (obj.is_null())
83     return 0;
84   return Java_TabBase_getSyncId(env, obj.obj());
85 }
86
87 base::string16 TabAndroid::GetTitle() const {
88   JNIEnv* env = base::android::AttachCurrentThread();
89   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
90   if (obj.is_null())
91     return base::string16();
92   return base::android::ConvertJavaStringToUTF16(
93       Java_TabBase_getTitle(env, obj.obj()));
94 }
95
96 GURL TabAndroid::GetURL() const {
97   JNIEnv* env = base::android::AttachCurrentThread();
98   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
99   if (obj.is_null())
100     return GURL::EmptyGURL();
101   return GURL(base::android::ConvertJavaStringToUTF8(
102       Java_TabBase_getUrl(env, obj.obj())));
103 }
104
105 bool TabAndroid::RestoreIfNeeded() {
106   JNIEnv* env = base::android::AttachCurrentThread();
107   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
108   if (obj.is_null())
109     return false;
110   return Java_TabBase_restoreIfNeeded(env, obj.obj());
111 }
112
113 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
114   if (!web_contents())
115     return NULL;
116
117   return content::ContentViewCore::FromWebContents(web_contents());
118 }
119
120 Profile* TabAndroid::GetProfile() const {
121   if (!web_contents())
122     return NULL;
123
124   return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
125 }
126
127 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
128   return synced_tab_delegate_.get();
129 }
130
131 void TabAndroid::SetSyncId(int sync_id) {
132   JNIEnv* env = base::android::AttachCurrentThread();
133   ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
134   if (obj.is_null())
135     return;
136   Java_TabBase_setSyncId(env, obj.obj(), sync_id);
137 }
138
139 void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) {
140   NOTIMPLEMENTED();
141 }
142
143 void TabAndroid::OnReceivedHttpAuthRequest(jobject auth_handler,
144                                            const base::string16& host,
145                                            const base::string16& realm) {
146   NOTIMPLEMENTED();
147 }
148
149 void TabAndroid::AddShortcutToBookmark(const GURL& url,
150                                        const base::string16& title,
151                                        const SkBitmap& skbitmap,
152                                        int r_value,
153                                        int g_value,
154                                        int b_value) {
155   NOTREACHED();
156 }
157
158 void TabAndroid::EditBookmark(int64 node_id,
159                               const base::string16& node_title,
160                               bool is_folder,
161                               bool is_partner_bookmark) {
162   NOTREACHED();
163 }
164
165 void TabAndroid::OnNewTabPageReady() {
166   NOTREACHED();
167 }
168
169 bool TabAndroid::ShouldWelcomePageLinkToTermsOfService() {
170   NOTIMPLEMENTED();
171   return false;
172 }
173
174 void TabAndroid::SwapTabContents(content::WebContents* old_contents,
175                                  content::WebContents* new_contents,
176                                  bool did_start_load,
177                                  bool did_finish_load) {
178   JNIEnv* env = base::android::AttachCurrentThread();
179
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(
184               env,
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);
189
190   Java_TabBase_swapWebContents(
191       env,
192       weak_java_tab_.get(env).obj(),
193       reinterpret_cast<intptr_t>(new_contents),
194       did_start_load,
195       did_finish_load);
196 }
197
198 void TabAndroid::Observe(int type,
199                          const content::NotificationSource& source,
200                          const content::NotificationDetails& details) {
201   JNIEnv* env = base::android::AttachCurrentThread();
202   switch (type) {
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
209         // boundary.
210         int num_popups = 0;
211         PopupBlockerTabHelper* popup_blocker_helper =
212             PopupBlockerTabHelper::FromWebContents(web_contents());
213         if (popup_blocker_helper)
214           num_popups = popup_blocker_helper->GetBlockedPopupsCount();
215
216         if (num_popups > 0)
217           PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups);
218
219         settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS);
220       }
221       break;
222     }
223     case chrome::NOTIFICATION_FAVICON_UPDATED:
224       Java_TabBase_onFaviconUpdated(env, weak_java_tab_.get(env).obj());
225       break;
226     case content::NOTIFICATION_NAV_ENTRY_CHANGED:
227       Java_TabBase_onNavEntryChanged(env, weak_java_tab_.get(env).obj());
228       break;
229     default:
230       NOTREACHED() << "Unexpected notification " << type;
231       break;
232   }
233 }
234
235 void TabAndroid::Destroy(JNIEnv* env, jobject obj) {
236   delete this;
237 }
238
239 void TabAndroid::InitWebContents(JNIEnv* env,
240                                  jobject obj,
241                                  jboolean incognito,
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,
247                                                          jcontent_view_core);
248   DCHECK(content_view_core);
249   DCHECK(content_view_core->GetWebContents());
250
251   web_contents_.reset(content_view_core->GetWebContents());
252   TabHelpers::AttachTabHelpers(web_contents_.get());
253
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());
266
267   notification_registrar_.Add(
268       this,
269       chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
270       content::Source<content::WebContents>(web_contents()));
271   notification_registrar_.Add(
272       this,
273       chrome::NOTIFICATION_FAVICON_UPDATED,
274       content::Source<content::WebContents>(web_contents()));
275   notification_registrar_.Add(
276       this,
277       content::NOTIFICATION_NAV_ENTRY_CHANGED,
278       content::Source<content::NavigationController>(
279            &web_contents()->GetController()));
280
281   synced_tab_delegate_->SetWebContents(web_contents());
282
283   // Set the window ID if there is a valid TabModel.
284   TabModel* model = TabModelList::GetTabModelWithProfile(GetProfile());
285   if (model) {
286     SessionID window_id;
287     window_id.set_id(model->GetSessionId());
288
289     SessionTabHelper* session_tab_helper =
290         SessionTabHelper::FromWebContents(web_contents());
291     session_tab_helper->SetWindowID(window_id);
292   }
293
294   // Verify that the WebContents this tab represents matches the expected
295   // off the record state.
296   CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito);
297 }
298
299 void TabAndroid::DestroyWebContents(JNIEnv* env,
300                                     jobject obj,
301                                     jboolean delete_native) {
302   DCHECK(web_contents());
303
304   notification_registrar_.Remove(
305       this,
306       chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
307       content::Source<content::WebContents>(web_contents()));
308   notification_registrar_.Remove(
309       this,
310       chrome::NOTIFICATION_FAVICON_UPDATED,
311       content::Source<content::WebContents>(web_contents()));
312
313   web_contents()->SetDelegate(NULL);
314
315   if (delete_native) {
316     web_contents_.reset();
317     synced_tab_delegate_->ResetWebContents();
318   } else {
319     // Release the WebContents so it does not get deleted by the scoped_ptr.
320     ignore_result(web_contents_.release());
321   }
322 }
323
324 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetWebContents(
325     JNIEnv* env,
326     jobject obj) {
327   if (!web_contents_.get())
328     return base::android::ScopedJavaLocalRef<jobject>();
329   return web_contents_->GetJavaWebContents();
330 }
331
332 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid(
333     JNIEnv* env,
334     jobject obj) {
335   Profile* profile = GetProfile();
336   if (!profile)
337     return base::android::ScopedJavaLocalRef<jobject>();
338   ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
339   if (!profile_android)
340     return base::android::ScopedJavaLocalRef<jobject>();
341
342   return profile_android->GetJavaObject();
343 }
344
345 ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env,
346                                                          jobject obj) {
347   return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents());
348 }
349
350 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env,
351                                                      jobject obj,
352                                                      jstring jurl,
353                                                      jstring jtitle) {
354   DCHECK(web_contents());
355
356   base::string16 title;
357   if (jtitle)
358     title = base::android::ConvertJavaStringToUTF16(env, jtitle);
359
360   std::string url;
361   if (jurl)
362     url = base::android::ConvertJavaStringToUTF8(env, jurl);
363
364   content::NavigationEntry* entry =
365       web_contents()->GetController().GetVisibleEntry();
366   if (entry && url == entry->GetVirtualURL().spec())
367     entry->SetTitle(title);
368 }
369
370 bool TabAndroid::Print(JNIEnv* env, jobject obj) {
371   if (!web_contents())
372     return false;
373
374   printing::PrintViewManagerBasic::CreateForWebContents(web_contents());
375   printing::PrintViewManagerBasic* print_view_manager =
376       printing::PrintViewManagerBasic::FromWebContents(web_contents());
377   if (print_view_manager == NULL)
378     return false;
379
380   print_view_manager->PrintNow();
381   return true;
382 }
383
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);
388 }
389
390 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
391   return RegisterNativesImpl(env);
392 }