tab_android.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
34TabAndroid* 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
46TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
47  return reinterpret_cast<TabAndroid*>(Java_TabBase_getNativePtr(env, obj));
48}
49
50TabAndroid::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
57TabAndroid::~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
66base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() {
67  JNIEnv* env = base::android::AttachCurrentThread();
68  return weak_java_tab_.get(env);
69}
70
71int 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
79int 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
87base::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
96GURL 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
105bool 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
113content::ContentViewCore* TabAndroid::GetContentViewCore() const {
114  if (!web_contents())
115    return NULL;
116
117  return content::ContentViewCore::FromWebContents(web_contents());
118}
119
120Profile* TabAndroid::GetProfile() const {
121  if (!web_contents())
122    return NULL;
123
124  return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
125}
126
127browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
128  return synced_tab_delegate_.get();
129}
130
131void 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
139void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) {
140  NOTIMPLEMENTED();
141}
142
143void TabAndroid::OnReceivedHttpAuthRequest(jobject auth_handler,
144                                           const base::string16& host,
145                                           const base::string16& realm) {
146  NOTIMPLEMENTED();
147}
148
149void 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
158void TabAndroid::EditBookmark(int64 node_id,
159                              const base::string16& node_title,
160                              bool is_folder,
161                              bool is_partner_bookmark) {
162  NOTREACHED();
163}
164
165void TabAndroid::OnNewTabPageReady() {
166  NOTREACHED();
167}
168
169bool TabAndroid::ShouldWelcomePageLinkToTermsOfService() {
170  NOTIMPLEMENTED();
171  return false;
172}
173
174void 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
198void 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
235void TabAndroid::Destroy(JNIEnv* env, jobject obj) {
236  delete this;
237}
238
239void 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
299void 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
324base::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
332base::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
345ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env,
346                                                         jobject obj) {
347  return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents());
348}
349
350void 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
370bool 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
384static 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
390bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
391  return RegisterNativesImpl(env);
392}
393