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.
5 #include "chrome/browser/android/tab_android.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/debug/trace_event.h"
11 #include "chrome/browser/android/chrome_web_contents_delegate_android.h"
12 #include "chrome/browser/browser_about_handler.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
15 #include "chrome/browser/favicon/favicon_tab_helper.h"
16 #include "chrome/browser/google/google_url_tracker_factory.h"
17 #include "chrome/browser/infobars/infobar_service.h"
18 #include "chrome/browser/prerender/prerender_contents.h"
19 #include "chrome/browser/prerender/prerender_manager.h"
20 #include "chrome/browser/prerender/prerender_manager_factory.h"
21 #include "chrome/browser/printing/print_view_manager_basic.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/profiles/profile_android.h"
24 #include "chrome/browser/search/search.h"
25 #include "chrome/browser/sessions/session_tab_helper.h"
26 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
27 #include "chrome/browser/tab_contents/tab_util.h"
28 #include "chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h"
29 #include "chrome/browser/ui/android/context_menu_helper.h"
30 #include "chrome/browser/ui/android/infobars/infobar_container_android.h"
31 #include "chrome/browser/ui/android/tab_model/tab_model.h"
32 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
33 #include "chrome/browser/ui/android/window_android_helper.h"
34 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
35 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
36 #include "chrome/browser/ui/search/search_tab_helper.h"
37 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
38 #include "chrome/browser/ui/tab_helpers.h"
39 #include "chrome/common/url_constants.h"
40 #include "components/google/core/browser/google_url_tracker.h"
41 #include "components/google/core/browser/google_util.h"
42 #include "components/infobars/core/infobar_container.h"
43 #include "components/url_fixer/url_fixer.h"
44 #include "content/public/browser/android/content_view_core.h"
45 #include "content/public/browser/navigation_entry.h"
46 #include "content/public/browser/notification_service.h"
47 #include "content/public/browser/user_metrics.h"
48 #include "content/public/browser/web_contents.h"
49 #include "jni/Tab_jni.h"
50 #include "skia/ext/image_operations.h"
51 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
52 #include "ui/base/resource/resource_bundle.h"
53 #include "ui/base/window_open_disposition.h"
54 #include "ui/gfx/android/device_display_info.h"
55 #include "ui/gfx/android/java_bitmap.h"
56 #include "ui/gfx/favicon_size.h"
57 #include "ui/gfx/image/image_skia.h"
59 using content::GlobalRequestID
;
60 using content::NavigationController
;
61 using content::WebContents
;
65 WebContents
* CreateTargetContents(const chrome::NavigateParams
& params
,
67 Profile
* profile
= params
.initiating_profile
;
69 if (profile
->IsOffTheRecord() || params
.disposition
== OFF_THE_RECORD
) {
70 profile
= profile
->GetOffTheRecordProfile();
72 WebContents::CreateParams
create_params(
73 profile
, tab_util::GetSiteInstanceForNewTab(profile
, url
));
74 if (params
.source_contents
) {
75 create_params
.initial_size
=
76 params
.source_contents
->GetContainerBounds().size();
77 if (params
.should_set_opener
)
78 create_params
.opener
= params
.source_contents
;
80 if (params
.disposition
== NEW_BACKGROUND_TAB
)
81 create_params
.initially_hidden
= true;
83 WebContents
* target_contents
= WebContents::Create(create_params
);
85 return target_contents
;
88 bool MaybeSwapWithPrerender(const GURL
& url
, chrome::NavigateParams
* params
) {
90 Profile::FromBrowserContext(params
->target_contents
->GetBrowserContext());
92 prerender::PrerenderManager
* prerender_manager
=
93 prerender::PrerenderManagerFactory::GetForProfile(profile
);
94 if (!prerender_manager
)
96 return prerender_manager
->MaybeUsePrerenderedPage(url
, params
);
101 TabAndroid
* TabAndroid::FromWebContents(content::WebContents
* web_contents
) {
102 CoreTabHelper
* core_tab_helper
= CoreTabHelper::FromWebContents(web_contents
);
103 if (!core_tab_helper
)
106 CoreTabHelperDelegate
* core_delegate
= core_tab_helper
->delegate();
110 return static_cast<TabAndroid
*>(core_delegate
);
113 TabAndroid
* TabAndroid::GetNativeTab(JNIEnv
* env
, jobject obj
) {
114 return reinterpret_cast<TabAndroid
*>(Java_Tab_getNativePtr(env
, obj
));
117 void TabAndroid::AttachTabHelpers(content::WebContents
* web_contents
) {
118 DCHECK(web_contents
);
120 TabHelpers::AttachTabHelpers(web_contents
);
123 TabAndroid::TabAndroid(JNIEnv
* env
, jobject obj
)
124 : weak_java_tab_(env
, obj
),
125 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
126 Java_Tab_setNativePtr(env
, obj
, reinterpret_cast<intptr_t>(this));
129 TabAndroid::~TabAndroid() {
130 JNIEnv
* env
= base::android::AttachCurrentThread();
131 Java_Tab_clearNativePtr(env
, weak_java_tab_
.get(env
).obj());
134 base::android::ScopedJavaLocalRef
<jobject
> TabAndroid::GetJavaObject() {
135 JNIEnv
* env
= base::android::AttachCurrentThread();
136 return weak_java_tab_
.get(env
);
139 int TabAndroid::GetAndroidId() const {
140 JNIEnv
* env
= base::android::AttachCurrentThread();
141 return Java_Tab_getId(env
, weak_java_tab_
.get(env
).obj());
144 int TabAndroid::GetSyncId() const {
145 JNIEnv
* env
= base::android::AttachCurrentThread();
146 return Java_Tab_getSyncId(env
, weak_java_tab_
.get(env
).obj());
149 base::string16
TabAndroid::GetTitle() const {
150 JNIEnv
* env
= base::android::AttachCurrentThread();
151 return base::android::ConvertJavaStringToUTF16(
152 Java_Tab_getTitle(env
, weak_java_tab_
.get(env
).obj()));
155 GURL
TabAndroid::GetURL() const {
156 JNIEnv
* env
= base::android::AttachCurrentThread();
157 return GURL(base::android::ConvertJavaStringToUTF8(
158 Java_Tab_getUrl(env
, weak_java_tab_
.get(env
).obj())));
161 bool TabAndroid::LoadIfNeeded() {
162 JNIEnv
* env
= base::android::AttachCurrentThread();
163 return Java_Tab_loadIfNeeded(env
, weak_java_tab_
.get(env
).obj());
166 content::ContentViewCore
* TabAndroid::GetContentViewCore() const {
170 return content::ContentViewCore::FromWebContents(web_contents());
173 Profile
* TabAndroid::GetProfile() const {
177 return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
180 browser_sync::SyncedTabDelegate
* TabAndroid::GetSyncedTabDelegate() const {
181 return synced_tab_delegate_
.get();
184 void TabAndroid::SetWindowSessionID(SessionID::id_type window_id
) {
185 session_window_id_
.set_id(window_id
);
190 SessionTabHelper
* session_tab_helper
=
191 SessionTabHelper::FromWebContents(web_contents());
192 session_tab_helper
->SetWindowID(session_window_id_
);
195 void TabAndroid::SetSyncId(int sync_id
) {
196 JNIEnv
* env
= base::android::AttachCurrentThread();
197 Java_Tab_setSyncId(env
, weak_java_tab_
.get(env
).obj(), sync_id
);
200 void TabAndroid::HandlePopupNavigation(chrome::NavigateParams
* params
) {
201 if (params
->disposition
!= SUPPRESS_OPEN
&&
202 params
->disposition
!= SAVE_TO_DISK
&&
203 params
->disposition
!= IGNORE_ACTION
) {
204 if (!params
->url
.is_empty()) {
205 bool was_blocked
= false;
206 GURL
url(params
->url
);
207 if (params
->disposition
== CURRENT_TAB
) {
208 params
->target_contents
= web_contents_
.get();
209 if (!MaybeSwapWithPrerender(url
, params
)) {
210 NavigationController::LoadURLParams
load_url_params(url
);
211 MakeLoadURLParams(params
, &load_url_params
);
212 params
->target_contents
->GetController().LoadURLWithParams(
216 params
->target_contents
= CreateTargetContents(*params
, url
);
217 NavigationController::LoadURLParams
load_url_params(url
);
218 MakeLoadURLParams(params
, &load_url_params
);
219 params
->target_contents
->GetController().LoadURLWithParams(
221 web_contents_delegate_
->AddNewContents(params
->source_contents
,
222 params
->target_contents
,
224 params
->window_bounds
,
225 params
->user_gesture
,
228 params
->target_contents
= NULL
;
234 bool TabAndroid::HasPrerenderedUrl(GURL gurl
) {
235 prerender::PrerenderManager
* prerender_manager
= GetPrerenderManager();
236 if (!prerender_manager
)
239 std::vector
<content::WebContents
*> contents
=
240 prerender_manager
->GetAllPrerenderingContents();
241 prerender::PrerenderContents
* prerender_contents
;
242 for (size_t i
= 0; i
< contents
.size(); ++i
) {
243 prerender_contents
= prerender_manager
->
244 GetPrerenderContents(contents
.at(i
));
245 if (prerender_contents
->prerender_url() == gurl
&&
246 prerender_contents
->has_finished_loading()) {
253 void TabAndroid::MakeLoadURLParams(
254 chrome::NavigateParams
* params
,
255 NavigationController::LoadURLParams
* load_url_params
) {
256 load_url_params
->referrer
= params
->referrer
;
257 load_url_params
->frame_tree_node_id
= params
->frame_tree_node_id
;
258 load_url_params
->redirect_chain
= params
->redirect_chain
;
259 load_url_params
->transition_type
= params
->transition
;
260 load_url_params
->extra_headers
= params
->extra_headers
;
261 load_url_params
->should_replace_current_entry
=
262 params
->should_replace_current_entry
;
264 if (params
->transferred_global_request_id
!= GlobalRequestID()) {
265 load_url_params
->transferred_global_request_id
=
266 params
->transferred_global_request_id
;
268 load_url_params
->is_renderer_initiated
= params
->is_renderer_initiated
;
270 // Only allows the browser-initiated navigation to use POST.
271 if (params
->uses_post
&& !params
->is_renderer_initiated
) {
272 load_url_params
->load_type
=
273 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST
;
274 load_url_params
->browser_initiated_post_data
=
275 params
->browser_initiated_post_data
;
279 void TabAndroid::SwapTabContents(content::WebContents
* old_contents
,
280 content::WebContents
* new_contents
,
282 bool did_finish_load
) {
283 JNIEnv
* env
= base::android::AttachCurrentThread();
285 // We need to notify the native InfobarContainer so infobars can be swapped.
286 InfoBarContainerAndroid
* infobar_container
=
287 reinterpret_cast<InfoBarContainerAndroid
*>(
288 Java_Tab_getNativeInfoBarContainer(
290 weak_java_tab_
.get(env
).obj()));
291 InfoBarService
* new_infobar_service
=
292 new_contents
? InfoBarService::FromWebContents(new_contents
) : NULL
;
293 infobar_container
->ChangeInfoBarManager(new_infobar_service
);
295 Java_Tab_swapWebContents(
297 weak_java_tab_
.get(env
).obj(),
298 reinterpret_cast<intptr_t>(new_contents
),
303 void TabAndroid::OnWebContentsInstantSupportDisabled(
304 const content::WebContents
* contents
) {
306 if (web_contents() != contents
)
309 JNIEnv
* env
= base::android::AttachCurrentThread();
310 Java_Tab_onWebContentsInstantSupportDisabled(env
,
311 weak_java_tab_
.get(env
).obj());
314 void TabAndroid::Observe(int type
,
315 const content::NotificationSource
& source
,
316 const content::NotificationDetails
& details
) {
317 JNIEnv
* env
= base::android::AttachCurrentThread();
319 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
: {
320 TabSpecificContentSettings
* settings
=
321 TabSpecificContentSettings::FromWebContents(web_contents());
322 if (!settings
->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS
)) {
323 // TODO(dfalcantara): Create an InfoBarDelegate to keep the
324 // PopupBlockedInfoBar logic native-side instead of straddling the JNI
327 PopupBlockerTabHelper
* popup_blocker_helper
=
328 PopupBlockerTabHelper::FromWebContents(web_contents());
329 if (popup_blocker_helper
)
330 num_popups
= popup_blocker_helper
->GetBlockedPopupsCount();
333 PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups
);
335 settings
->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS
);
339 case chrome::NOTIFICATION_FAVICON_UPDATED
:
340 Java_Tab_onFaviconUpdated(env
, weak_java_tab_
.get(env
).obj());
342 case content::NOTIFICATION_NAV_ENTRY_CHANGED
:
343 Java_Tab_onNavEntryChanged(env
, weak_java_tab_
.get(env
).obj());
346 NOTREACHED() << "Unexpected notification " << type
;
351 void TabAndroid::Destroy(JNIEnv
* env
, jobject obj
) {
355 void TabAndroid::InitWebContents(JNIEnv
* env
,
358 jobject jcontent_view_core
,
359 jobject jweb_contents_delegate
,
360 jobject jcontext_menu_populator
) {
361 content::ContentViewCore
* content_view_core
=
362 content::ContentViewCore::GetNativeContentViewCore(env
,
364 DCHECK(content_view_core
);
365 DCHECK(content_view_core
->GetWebContents());
367 web_contents_
.reset(content_view_core
->GetWebContents());
368 AttachTabHelpers(web_contents_
.get());
370 SetWindowSessionID(session_window_id_
.id());
372 session_tab_id_
.set_id(
373 SessionTabHelper::FromWebContents(web_contents())->session_id().id());
374 ContextMenuHelper::FromWebContents(web_contents())->SetPopulator(
375 jcontext_menu_populator
);
376 WindowAndroidHelper::FromWebContents(web_contents())->
377 SetWindowAndroid(content_view_core
->GetWindowAndroid());
378 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this);
379 SearchTabHelper::FromWebContents(web_contents())->set_delegate(this);
380 web_contents_delegate_
.reset(
381 new chrome::android::ChromeWebContentsDelegateAndroid(
382 env
, jweb_contents_delegate
));
383 web_contents_delegate_
->LoadProgressChanged(web_contents(), 0);
384 web_contents()->SetDelegate(web_contents_delegate_
.get());
386 notification_registrar_
.Add(
388 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
389 content::Source
<content::WebContents
>(web_contents()));
390 notification_registrar_
.Add(
392 chrome::NOTIFICATION_FAVICON_UPDATED
,
393 content::Source
<content::WebContents
>(web_contents()));
394 notification_registrar_
.Add(
396 content::NOTIFICATION_NAV_ENTRY_CHANGED
,
397 content::Source
<content::NavigationController
>(
398 &web_contents()->GetController()));
400 synced_tab_delegate_
->SetWebContents(web_contents());
402 // Verify that the WebContents this tab represents matches the expected
403 // off the record state.
404 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito
);
407 void TabAndroid::DestroyWebContents(JNIEnv
* env
,
409 jboolean delete_native
) {
410 DCHECK(web_contents());
412 notification_registrar_
.Remove(
414 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
415 content::Source
<content::WebContents
>(web_contents()));
416 notification_registrar_
.Remove(
418 chrome::NOTIFICATION_FAVICON_UPDATED
,
419 content::Source
<content::WebContents
>(web_contents()));
420 notification_registrar_
.Remove(
422 content::NOTIFICATION_NAV_ENTRY_CHANGED
,
423 content::Source
<content::NavigationController
>(
424 &web_contents()->GetController()));
426 web_contents()->SetDelegate(NULL
);
429 web_contents_
.reset();
430 synced_tab_delegate_
->ResetWebContents();
432 // Release the WebContents so it does not get deleted by the scoped_ptr.
433 ignore_result(web_contents_
.release());
437 base::android::ScopedJavaLocalRef
<jobject
> TabAndroid::GetProfileAndroid(
440 Profile
* profile
= GetProfile();
442 return base::android::ScopedJavaLocalRef
<jobject
>();
443 ProfileAndroid
* profile_android
= ProfileAndroid::FromProfile(profile
);
444 if (!profile_android
)
445 return base::android::ScopedJavaLocalRef
<jobject
>();
447 return profile_android
->GetJavaObject();
450 TabAndroid::TabLoadStatus
TabAndroid::LoadUrl(JNIEnv
* env
,
453 jstring j_extra_headers
,
454 jbyteArray j_post_data
,
455 jint page_transition
,
456 jstring j_referrer_url
,
457 jint referrer_policy
,
458 jboolean is_renderer_initiated
) {
460 return PAGE_LOAD_FAILED
;
462 GURL
gurl(base::android::ConvertJavaStringToUTF8(env
, url
));
464 return PAGE_LOAD_FAILED
;
466 // If the page was prerendered, use it.
467 // Note in incognito mode, we don't have a PrerenderManager.
469 prerender::PrerenderManager
* prerender_manager
=
470 prerender::PrerenderManagerFactory::GetForProfile(GetProfile());
471 if (prerender_manager
) {
472 bool prefetched_page_loaded
= HasPrerenderedUrl(gurl
);
473 // Getting the load status before MaybeUsePrerenderedPage() b/c it resets.
474 chrome::NavigateParams
params(NULL
, web_contents());
475 InstantSearchPrerenderer
* prerenderer
=
476 InstantSearchPrerenderer::GetForProfile(GetProfile());
478 const base::string16
& search_terms
=
479 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl
);
480 if (!search_terms
.empty() &&
481 prerenderer
->CanCommitQuery(web_contents_
.get(), search_terms
)) {
482 prerenderer
->Commit(search_terms
);
484 if (prerenderer
->UsePrerenderedPage(gurl
, ¶ms
))
485 return FULL_PRERENDERED_PAGE_LOAD
;
487 prerenderer
->Cancel();
489 if (prerender_manager
->MaybeUsePrerenderedPage(gurl
, ¶ms
)) {
490 return prefetched_page_loaded
?
491 FULL_PRERENDERED_PAGE_LOAD
: PARTIAL_PRERENDERED_PAGE_LOAD
;
496 url_fixer::FixupURL(gurl
.possibly_invalid_spec(), std::string()));
497 if (!fixed_url
.is_valid())
498 return PAGE_LOAD_FAILED
;
500 if (!HandleNonNavigationAboutURL(fixed_url
)) {
501 // Notify the GoogleURLTracker of searches, it might want to change the
502 // actual Google site used (for instance when in the UK, google.co.uk, when
503 // in the US google.com).
504 // Note that this needs to happen before we initiate the navigation as the
505 // GoogleURLTracker uses the navigation pending notification to trigger the
507 if (google_util::IsGoogleSearchUrl(fixed_url
) &&
508 (page_transition
& ui::PAGE_TRANSITION_GENERATED
)) {
509 GoogleURLTracker
* tracker
=
510 GoogleURLTrackerFactory::GetForProfile(GetProfile());
512 tracker
->SearchCommitted();
515 // Record UMA "ShowHistory" here. That way it'll pick up both user
516 // typing chrome://history as well as selecting from the drop down menu.
517 if (fixed_url
.spec() == chrome::kChromeUIHistoryURL
) {
518 content::RecordAction(base::UserMetricsAction("ShowHistory"));
521 content::NavigationController::LoadURLParams
load_params(fixed_url
);
522 if (j_extra_headers
) {
523 load_params
.extra_headers
= base::android::ConvertJavaStringToUTF8(
528 load_params
.load_type
=
529 content::NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST
;
530 std::vector
<uint8
> post_data
;
531 base::android::JavaByteArrayToByteVector(env
, j_post_data
, &post_data
);
532 load_params
.browser_initiated_post_data
=
533 base::RefCountedBytes::TakeVector(&post_data
);
535 load_params
.transition_type
=
536 ui::PageTransitionFromInt(page_transition
);
537 if (j_referrer_url
) {
538 load_params
.referrer
= content::Referrer(
539 GURL(base::android::ConvertJavaStringToUTF8(env
, j_referrer_url
)),
540 static_cast<blink::WebReferrerPolicy
>(referrer_policy
));
542 const base::string16 search_terms
=
543 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl
);
544 SearchTabHelper
* search_tab_helper
=
545 SearchTabHelper::FromWebContents(web_contents_
.get());
546 if (!search_terms
.empty() && search_tab_helper
&&
547 search_tab_helper
->SupportsInstant()) {
548 search_tab_helper
->Submit(search_terms
);
549 return DEFAULT_PAGE_LOAD
;
551 load_params
.is_renderer_initiated
= is_renderer_initiated
;
552 web_contents()->GetController().LoadURLWithParams(load_params
);
554 return DEFAULT_PAGE_LOAD
;
557 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv
* env
,
561 DCHECK(web_contents());
563 base::string16 title
;
565 title
= base::android::ConvertJavaStringToUTF16(env
, jtitle
);
569 url
= base::android::ConvertJavaStringToUTF8(env
, jurl
);
571 content::NavigationEntry
* entry
=
572 web_contents()->GetController().GetVisibleEntry();
573 if (entry
&& url
== entry
->GetVirtualURL().spec())
574 entry
->SetTitle(title
);
577 bool TabAndroid::Print(JNIEnv
* env
, jobject obj
) {
581 printing::PrintViewManagerBasic::CreateForWebContents(web_contents());
582 printing::PrintViewManagerBasic
* print_view_manager
=
583 printing::PrintViewManagerBasic::FromWebContents(web_contents());
584 if (print_view_manager
== NULL
)
587 print_view_manager
->PrintNow();
591 ScopedJavaLocalRef
<jobject
> TabAndroid::GetFavicon(JNIEnv
* env
, jobject obj
) {
592 ScopedJavaLocalRef
<jobject
> bitmap
;
593 FaviconTabHelper
* favicon_tab_helper
=
594 FaviconTabHelper::FromWebContents(web_contents_
.get());
596 if (!favicon_tab_helper
)
599 // If the favicon isn't valid, it will return a default bitmap.
602 favicon_tab_helper
->GetFavicon()
605 ResourceBundle::GetSharedInstance().GetMaxScaleFactor())
608 if (favicon
.empty()) {
609 favicon
= favicon_tab_helper
->GetFavicon().AsBitmap();
612 if (!favicon
.empty()) {
613 gfx::DeviceDisplayInfo device_info
;
614 const float device_scale_factor
= device_info
.GetDIPScale();
615 int target_size_dip
= device_scale_factor
* gfx::kFaviconSize
;
616 if (favicon
.width() != target_size_dip
||
617 favicon
.height() != target_size_dip
) {
619 skia::ImageOperations::Resize(favicon
,
620 skia::ImageOperations::RESIZE_BEST
,
625 bitmap
= gfx::ConvertToJavaBitmap(&favicon
);
630 jboolean
TabAndroid::IsFaviconValid(JNIEnv
* env
, jobject jobj
) {
631 return web_contents() &&
632 FaviconTabHelper::FromWebContents(web_contents())->FaviconIsValid();
635 prerender::PrerenderManager
* TabAndroid::GetPrerenderManager() const {
636 Profile
* profile
= GetProfile();
639 return prerender::PrerenderManagerFactory::GetForProfile(profile
);
642 static void Init(JNIEnv
* env
, jobject obj
) {
643 TRACE_EVENT0("native", "TabAndroid::Init");
644 // This will automatically bind to the Java object and pass ownership there.
645 new TabAndroid(env
, obj
);
648 bool TabAndroid::RegisterTabAndroid(JNIEnv
* env
) {
649 return RegisterNativesImpl(env
);