app_list: Re-enable people search.
[chromium-blink-merge.git] / chrome / browser / android / tab_android.cc
blobe7ce1c8d17890596a60fb6293005ec400bed861e
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 "base/metrics/histogram.h"
12 #include "chrome/browser/android/chrome_web_contents_delegate_android.h"
13 #include "chrome/browser/android/uma_utils.h"
14 #include "chrome/browser/browser_about_handler.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
17 #include "chrome/browser/favicon/favicon_tab_helper.h"
18 #include "chrome/browser/infobars/infobar_service.h"
19 #include "chrome/browser/prerender/prerender_contents.h"
20 #include "chrome/browser/prerender/prerender_manager.h"
21 #include "chrome/browser/prerender/prerender_manager_factory.h"
22 #include "chrome/browser/printing/print_view_manager_basic.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/profiles/profile_android.h"
25 #include "chrome/browser/search/instant_service.h"
26 #include "chrome/browser/search/instant_service_factory.h"
27 #include "chrome/browser/search/search.h"
28 #include "chrome/browser/sessions/session_tab_helper.h"
29 #include "chrome/browser/sessions/tab_restore_service.h"
30 #include "chrome/browser/sessions/tab_restore_service_factory.h"
31 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
32 #include "chrome/browser/tab_contents/tab_util.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/blocked_content/popup_blocker_tab_helper.h"
40 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
41 #include "chrome/browser/ui/search/search_tab_helper.h"
42 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
43 #include "chrome/browser/ui/tab_helpers.h"
44 #include "chrome/common/instant_types.h"
45 #include "chrome/common/render_messages.h"
46 #include "chrome/common/url_constants.h"
47 #include "components/infobars/core/infobar_container.h"
48 #include "components/navigation_interception/intercept_navigation_delegate.h"
49 #include "components/navigation_interception/navigation_params.h"
50 #include "components/url_fixer/url_fixer.h"
51 #include "content/public/browser/android/content_view_core.h"
52 #include "content/public/browser/browser_thread.h"
53 #include "content/public/browser/navigation_entry.h"
54 #include "content/public/browser/notification_service.h"
55 #include "content/public/browser/render_frame_host.h"
56 #include "content/public/browser/render_process_host.h"
57 #include "content/public/browser/user_metrics.h"
58 #include "content/public/browser/web_contents.h"
59 #include "content/public/common/top_controls_state.h"
60 #include "jni/Tab_jni.h"
61 #include "net/base/escape.h"
62 #include "skia/ext/image_operations.h"
63 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
64 #include "ui/base/resource/resource_bundle.h"
65 #include "ui/base/window_open_disposition.h"
66 #include "ui/gfx/android/device_display_info.h"
67 #include "ui/gfx/android/java_bitmap.h"
68 #include "ui/gfx/favicon_size.h"
69 #include "ui/gfx/image/image_skia.h"
71 using base::android::AttachCurrentThread;
72 using base::android::ConvertUTF8ToJavaString;
73 using base::android::ToJavaByteArray;
74 using content::BrowserThread;
75 using content::GlobalRequestID;
76 using content::NavigationController;
77 using content::WebContents;
78 using navigation_interception::InterceptNavigationDelegate;
79 using navigation_interception::NavigationParams;
81 namespace {
83 const int kImageSearchThumbnailMinSize = 300 * 300;
84 const int kImageSearchThumbnailMaxWidth = 600;
85 const int kImageSearchThumbnailMaxHeight = 600;
87 } // namespace
89 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
90 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
91 if (!core_tab_helper)
92 return NULL;
94 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
95 if (!core_delegate)
96 return NULL;
98 return static_cast<TabAndroid*>(core_delegate);
101 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
102 return reinterpret_cast<TabAndroid*>(Java_Tab_getNativePtr(env, obj));
105 void TabAndroid::AttachTabHelpers(content::WebContents* web_contents) {
106 DCHECK(web_contents);
108 TabHelpers::AttachTabHelpers(web_contents);
111 TabAndroid::TabAndroid(JNIEnv* env, jobject obj)
112 : weak_java_tab_(env, obj),
113 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
114 Java_Tab_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this));
117 TabAndroid::~TabAndroid() {
118 JNIEnv* env = base::android::AttachCurrentThread();
119 Java_Tab_clearNativePtr(env, weak_java_tab_.get(env).obj());
122 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() {
123 JNIEnv* env = base::android::AttachCurrentThread();
124 return weak_java_tab_.get(env);
127 int TabAndroid::GetAndroidId() const {
128 JNIEnv* env = base::android::AttachCurrentThread();
129 return Java_Tab_getId(env, weak_java_tab_.get(env).obj());
132 int TabAndroid::GetSyncId() const {
133 JNIEnv* env = base::android::AttachCurrentThread();
134 return Java_Tab_getSyncId(env, weak_java_tab_.get(env).obj());
137 base::string16 TabAndroid::GetTitle() const {
138 JNIEnv* env = base::android::AttachCurrentThread();
139 return base::android::ConvertJavaStringToUTF16(
140 Java_Tab_getTitle(env, weak_java_tab_.get(env).obj()));
143 GURL TabAndroid::GetURL() const {
144 JNIEnv* env = base::android::AttachCurrentThread();
145 return GURL(base::android::ConvertJavaStringToUTF8(
146 Java_Tab_getUrl(env, weak_java_tab_.get(env).obj())));
149 bool TabAndroid::LoadIfNeeded() {
150 JNIEnv* env = base::android::AttachCurrentThread();
151 return Java_Tab_loadIfNeeded(env, weak_java_tab_.get(env).obj());
154 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
155 if (!web_contents())
156 return NULL;
158 return content::ContentViewCore::FromWebContents(web_contents());
161 Profile* TabAndroid::GetProfile() const {
162 if (!web_contents())
163 return NULL;
165 return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
168 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
169 return synced_tab_delegate_.get();
172 void TabAndroid::SetWindowSessionID(SessionID::id_type window_id) {
173 session_window_id_.set_id(window_id);
175 if (!web_contents())
176 return;
178 SessionTabHelper* session_tab_helper =
179 SessionTabHelper::FromWebContents(web_contents());
180 session_tab_helper->SetWindowID(session_window_id_);
183 void TabAndroid::SetSyncId(int sync_id) {
184 JNIEnv* env = base::android::AttachCurrentThread();
185 Java_Tab_setSyncId(env, weak_java_tab_.get(env).obj(), sync_id);
188 void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) {
189 DCHECK(params->source_contents == web_contents());
190 DCHECK(params->target_contents == NULL ||
191 params->target_contents == web_contents());
193 WindowOpenDisposition disposition = params->disposition;
194 const GURL& url = params->url;
196 if (disposition == NEW_POPUP ||
197 disposition == NEW_FOREGROUND_TAB ||
198 disposition == NEW_BACKGROUND_TAB ||
199 disposition == NEW_WINDOW ||
200 disposition == OFF_THE_RECORD) {
201 JNIEnv* env = AttachCurrentThread();
202 ScopedJavaLocalRef<jobject> jobj = weak_java_tab_.get(env);
203 ScopedJavaLocalRef<jstring> jurl(ConvertUTF8ToJavaString(env, url.spec()));
204 ScopedJavaLocalRef<jstring> jheaders(
205 ConvertUTF8ToJavaString(env, params->extra_headers));
206 ScopedJavaLocalRef<jbyteArray> jpost_data;
207 if (params->uses_post &&
208 params->browser_initiated_post_data.get() &&
209 params->browser_initiated_post_data.get()->size()) {
210 jpost_data = ToJavaByteArray(
211 env,
212 reinterpret_cast<const uint8*>(
213 params->browser_initiated_post_data.get()->front()),
214 params->browser_initiated_post_data.get()->size());
216 Java_Tab_openNewTab(env,
217 jobj.obj(),
218 jurl.obj(),
219 jheaders.obj(),
220 jpost_data.obj(),
221 disposition,
222 params->should_set_opener,
223 params->is_renderer_initiated);
224 } else {
225 NOTIMPLEMENTED();
229 bool TabAndroid::HasPrerenderedUrl(GURL gurl) {
230 prerender::PrerenderManager* prerender_manager = GetPrerenderManager();
231 if (!prerender_manager)
232 return false;
234 std::vector<content::WebContents*> contents =
235 prerender_manager->GetAllPrerenderingContents();
236 prerender::PrerenderContents* prerender_contents;
237 for (size_t i = 0; i < contents.size(); ++i) {
238 prerender_contents = prerender_manager->
239 GetPrerenderContents(contents.at(i));
240 if (prerender_contents->prerender_url() == gurl &&
241 prerender_contents->has_finished_loading()) {
242 return true;
245 return false;
248 void TabAndroid::MakeLoadURLParams(
249 chrome::NavigateParams* params,
250 NavigationController::LoadURLParams* load_url_params) {
251 load_url_params->referrer = params->referrer;
252 load_url_params->frame_tree_node_id = params->frame_tree_node_id;
253 load_url_params->redirect_chain = params->redirect_chain;
254 load_url_params->transition_type = params->transition;
255 load_url_params->extra_headers = params->extra_headers;
256 load_url_params->should_replace_current_entry =
257 params->should_replace_current_entry;
259 if (params->transferred_global_request_id != GlobalRequestID()) {
260 load_url_params->transferred_global_request_id =
261 params->transferred_global_request_id;
263 load_url_params->is_renderer_initiated = params->is_renderer_initiated;
265 // Only allows the browser-initiated navigation to use POST.
266 if (params->uses_post && !params->is_renderer_initiated) {
267 load_url_params->load_type =
268 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
269 load_url_params->browser_initiated_post_data =
270 params->browser_initiated_post_data;
274 void TabAndroid::SwapTabContents(content::WebContents* old_contents,
275 content::WebContents* new_contents,
276 bool did_start_load,
277 bool did_finish_load) {
278 JNIEnv* env = base::android::AttachCurrentThread();
280 // We need to notify the native InfobarContainer so infobars can be swapped.
281 InfoBarContainerAndroid* infobar_container =
282 reinterpret_cast<InfoBarContainerAndroid*>(
283 Java_Tab_getNativeInfoBarContainer(
284 env,
285 weak_java_tab_.get(env).obj()));
286 InfoBarService* new_infobar_service =
287 new_contents ? InfoBarService::FromWebContents(new_contents) : NULL;
288 infobar_container->ChangeInfoBarManager(new_infobar_service);
290 Java_Tab_swapWebContents(
291 env,
292 weak_java_tab_.get(env).obj(),
293 reinterpret_cast<intptr_t>(new_contents),
294 did_start_load,
295 did_finish_load);
298 void TabAndroid::DefaultSearchProviderChanged() {
299 // TODO(kmadhusu): Move this function definition to a common place and update
300 // BrowserInstantController::DefaultSearchProviderChanged to use the same.
301 if (!web_contents())
302 return;
304 InstantService* instant_service =
305 InstantServiceFactory::GetForProfile(GetProfile());
306 if (!instant_service)
307 return;
309 // Send new search URLs to the renderer.
310 content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost();
311 instant_service->SendSearchURLsToRenderer(rph);
313 // Reload the contents to ensure that it gets assigned to a non-previledged
314 // renderer.
315 if (!instant_service->IsInstantProcess(rph->GetID()))
316 return;
317 web_contents()->GetController().Reload(false);
319 // As the reload was not triggered by the user we don't want to close any
320 // infobars. We have to tell the InfoBarService after the reload, otherwise it
321 // would ignore this call when
322 // WebContentsObserver::DidStartNavigationToPendingEntry is invoked.
323 InfoBarService::FromWebContents(web_contents())->set_ignore_next_reload();
326 void TabAndroid::OnWebContentsInstantSupportDisabled(
327 const content::WebContents* contents) {
328 DCHECK(contents);
329 if (web_contents() != contents)
330 return;
332 JNIEnv* env = base::android::AttachCurrentThread();
333 Java_Tab_onWebContentsInstantSupportDisabled(env,
334 weak_java_tab_.get(env).obj());
337 void TabAndroid::Observe(int type,
338 const content::NotificationSource& source,
339 const content::NotificationDetails& details) {
340 JNIEnv* env = base::android::AttachCurrentThread();
341 switch (type) {
342 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: {
343 TabSpecificContentSettings* settings =
344 TabSpecificContentSettings::FromWebContents(web_contents());
345 if (!settings->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS)) {
346 // TODO(dfalcantara): Create an InfoBarDelegate to keep the
347 // PopupBlockedInfoBar logic native-side instead of straddling the JNI
348 // boundary.
349 int num_popups = 0;
350 PopupBlockerTabHelper* popup_blocker_helper =
351 PopupBlockerTabHelper::FromWebContents(web_contents());
352 if (popup_blocker_helper)
353 num_popups = popup_blocker_helper->GetBlockedPopupsCount();
355 if (num_popups > 0)
356 PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups);
358 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS);
360 break;
362 case content::NOTIFICATION_NAV_ENTRY_CHANGED:
363 Java_Tab_onNavEntryChanged(env, weak_java_tab_.get(env).obj());
364 break;
365 default:
366 NOTREACHED() << "Unexpected notification " << type;
367 break;
371 void TabAndroid::OnFaviconAvailable(const gfx::Image& image) {
372 SkBitmap favicon = image.AsImageSkia().GetRepresentation(1.0f).sk_bitmap();
373 if (favicon.empty())
374 return;
376 JNIEnv *env = base::android::AttachCurrentThread();
377 Java_Tab_onFaviconAvailable(env, weak_java_tab_.get(env).obj(),
378 gfx::ConvertToJavaBitmap(&favicon).obj());
381 void TabAndroid::Destroy(JNIEnv* env, jobject obj) {
382 delete this;
385 void TabAndroid::InitWebContents(JNIEnv* env,
386 jobject obj,
387 jboolean incognito,
388 jobject jcontent_view_core,
389 jobject jweb_contents_delegate,
390 jobject jcontext_menu_populator) {
391 content::ContentViewCore* content_view_core =
392 content::ContentViewCore::GetNativeContentViewCore(env,
393 jcontent_view_core);
394 DCHECK(content_view_core);
395 DCHECK(content_view_core->GetWebContents());
397 web_contents_.reset(content_view_core->GetWebContents());
398 AttachTabHelpers(web_contents_.get());
400 SetWindowSessionID(session_window_id_.id());
402 session_tab_id_.set_id(
403 SessionTabHelper::FromWebContents(web_contents())->session_id().id());
404 ContextMenuHelper::FromWebContents(web_contents())->SetPopulator(
405 jcontext_menu_populator);
406 WindowAndroidHelper::FromWebContents(web_contents())->
407 SetWindowAndroid(content_view_core->GetWindowAndroid());
408 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this);
409 SearchTabHelper::FromWebContents(web_contents())->set_delegate(this);
410 web_contents_delegate_.reset(
411 new chrome::android::ChromeWebContentsDelegateAndroid(
412 env, jweb_contents_delegate));
413 web_contents_delegate_->LoadProgressChanged(web_contents(), 0);
414 web_contents()->SetDelegate(web_contents_delegate_.get());
416 notification_registrar_.Add(
417 this,
418 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
419 content::Source<content::WebContents>(web_contents()));
420 notification_registrar_.Add(
421 this,
422 content::NOTIFICATION_NAV_ENTRY_CHANGED,
423 content::Source<content::NavigationController>(
424 &web_contents()->GetController()));
426 FaviconTabHelper* favicon_tab_helper =
427 FaviconTabHelper::FromWebContents(web_contents_.get());
429 if (favicon_tab_helper)
430 favicon_tab_helper->AddObserver(this);
432 synced_tab_delegate_->SetWebContents(web_contents());
434 // Verify that the WebContents this tab represents matches the expected
435 // off the record state.
436 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito);
438 InstantService* instant_service =
439 InstantServiceFactory::GetForProfile(GetProfile());
440 if (instant_service)
441 instant_service->AddObserver(this);
444 void TabAndroid::DestroyWebContents(JNIEnv* env,
445 jobject obj,
446 jboolean delete_native) {
447 DCHECK(web_contents());
449 notification_registrar_.Remove(
450 this,
451 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
452 content::Source<content::WebContents>(web_contents()));
453 notification_registrar_.Remove(
454 this,
455 content::NOTIFICATION_NAV_ENTRY_CHANGED,
456 content::Source<content::NavigationController>(
457 &web_contents()->GetController()));
459 FaviconTabHelper* favicon_tab_helper =
460 FaviconTabHelper::FromWebContents(web_contents_.get());
462 if (favicon_tab_helper)
463 favicon_tab_helper->RemoveObserver(this);
465 InstantService* instant_service =
466 InstantServiceFactory::GetForProfile(GetProfile());
467 if (instant_service)
468 instant_service->RemoveObserver(this);
470 web_contents()->SetDelegate(NULL);
472 if (delete_native) {
473 web_contents_.reset();
474 synced_tab_delegate_->ResetWebContents();
475 } else {
476 // Release the WebContents so it does not get deleted by the scoped_ptr.
477 ignore_result(web_contents_.release());
481 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid(
482 JNIEnv* env,
483 jobject obj) {
484 Profile* profile = GetProfile();
485 if (!profile)
486 return base::android::ScopedJavaLocalRef<jobject>();
487 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
488 if (!profile_android)
489 return base::android::ScopedJavaLocalRef<jobject>();
491 return profile_android->GetJavaObject();
494 TabAndroid::TabLoadStatus TabAndroid::LoadUrl(JNIEnv* env,
495 jobject obj,
496 jstring url,
497 jstring j_extra_headers,
498 jbyteArray j_post_data,
499 jint page_transition,
500 jstring j_referrer_url,
501 jint referrer_policy,
502 jboolean is_renderer_initiated) {
503 if (!web_contents())
504 return PAGE_LOAD_FAILED;
506 GURL gurl(base::android::ConvertJavaStringToUTF8(env, url));
507 if (gurl.is_empty())
508 return PAGE_LOAD_FAILED;
510 // If the page was prerendered, use it.
511 // Note in incognito mode, we don't have a PrerenderManager.
513 prerender::PrerenderManager* prerender_manager =
514 prerender::PrerenderManagerFactory::GetForProfile(GetProfile());
515 if (prerender_manager) {
516 bool prefetched_page_loaded = HasPrerenderedUrl(gurl);
517 // Getting the load status before MaybeUsePrerenderedPage() b/c it resets.
518 chrome::NavigateParams params(NULL, web_contents());
519 InstantSearchPrerenderer* prerenderer =
520 InstantSearchPrerenderer::GetForProfile(GetProfile());
521 if (prerenderer) {
522 const base::string16& search_terms =
523 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl);
524 if (!search_terms.empty() &&
525 prerenderer->CanCommitQuery(web_contents_.get(), search_terms)) {
526 EmbeddedSearchRequestParams request_params(gurl);
527 prerenderer->Commit(search_terms, request_params);
529 if (prerenderer->UsePrerenderedPage(gurl, &params))
530 return FULL_PRERENDERED_PAGE_LOAD;
532 prerenderer->Cancel();
534 if (prerender_manager->MaybeUsePrerenderedPage(gurl, &params)) {
535 return prefetched_page_loaded ?
536 FULL_PRERENDERED_PAGE_LOAD : PARTIAL_PRERENDERED_PAGE_LOAD;
540 GURL fixed_url(
541 url_fixer::FixupURL(gurl.possibly_invalid_spec(), std::string()));
542 if (!fixed_url.is_valid())
543 return PAGE_LOAD_FAILED;
545 if (!HandleNonNavigationAboutURL(fixed_url)) {
546 // Record UMA "ShowHistory" here. That way it'll pick up both user
547 // typing chrome://history as well as selecting from the drop down menu.
548 if (fixed_url.spec() == chrome::kChromeUIHistoryURL) {
549 content::RecordAction(base::UserMetricsAction("ShowHistory"));
552 content::NavigationController::LoadURLParams load_params(fixed_url);
553 if (j_extra_headers) {
554 load_params.extra_headers = base::android::ConvertJavaStringToUTF8(
555 env,
556 j_extra_headers);
558 if (j_post_data) {
559 load_params.load_type =
560 content::NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
561 std::vector<uint8> post_data;
562 base::android::JavaByteArrayToByteVector(env, j_post_data, &post_data);
563 load_params.browser_initiated_post_data =
564 base::RefCountedBytes::TakeVector(&post_data);
566 load_params.transition_type =
567 ui::PageTransitionFromInt(page_transition);
568 if (j_referrer_url) {
569 load_params.referrer = content::Referrer(
570 GURL(base::android::ConvertJavaStringToUTF8(env, j_referrer_url)),
571 static_cast<blink::WebReferrerPolicy>(referrer_policy));
573 const base::string16 search_terms =
574 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl);
575 SearchTabHelper* search_tab_helper =
576 SearchTabHelper::FromWebContents(web_contents_.get());
577 if (!search_terms.empty() && search_tab_helper &&
578 search_tab_helper->SupportsInstant()) {
579 EmbeddedSearchRequestParams request_params(gurl);
580 search_tab_helper->Submit(search_terms, request_params);
581 return DEFAULT_PAGE_LOAD;
583 load_params.is_renderer_initiated = is_renderer_initiated;
584 web_contents()->GetController().LoadURLWithParams(load_params);
586 return DEFAULT_PAGE_LOAD;
589 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env,
590 jobject obj,
591 jstring jurl,
592 jstring jtitle) {
593 DCHECK(web_contents());
595 base::string16 title;
596 if (jtitle)
597 title = base::android::ConvertJavaStringToUTF16(env, jtitle);
599 std::string url;
600 if (jurl)
601 url = base::android::ConvertJavaStringToUTF8(env, jurl);
603 content::NavigationEntry* entry =
604 web_contents()->GetController().GetVisibleEntry();
605 if (entry && url == entry->GetVirtualURL().spec())
606 entry->SetTitle(title);
609 bool TabAndroid::Print(JNIEnv* env, jobject obj) {
610 if (!web_contents())
611 return false;
613 printing::PrintViewManagerBasic::CreateForWebContents(web_contents());
614 printing::PrintViewManagerBasic* print_view_manager =
615 printing::PrintViewManagerBasic::FromWebContents(web_contents());
616 if (print_view_manager == NULL)
617 return false;
619 print_view_manager->PrintNow();
620 return true;
623 void TabAndroid::SetPendingPrint() {
624 JNIEnv* env = base::android::AttachCurrentThread();
625 Java_Tab_setPendingPrint(env, weak_java_tab_.get(env).obj());
628 ScopedJavaLocalRef<jobject> TabAndroid::GetFavicon(JNIEnv* env,
629 jobject obj) {
631 ScopedJavaLocalRef<jobject> bitmap;
632 FaviconTabHelper* favicon_tab_helper =
633 FaviconTabHelper::FromWebContents(web_contents_.get());
635 if (!favicon_tab_helper)
636 return bitmap;
638 // Always return the default favicon in Android.
639 SkBitmap favicon = favicon_tab_helper->GetFavicon().AsBitmap();
640 if (!favicon.empty()) {
641 gfx::DeviceDisplayInfo device_info;
642 const float device_scale_factor = device_info.GetDIPScale();
643 int target_size_dip = device_scale_factor * gfx::kFaviconSize;
644 if (favicon.width() != target_size_dip ||
645 favicon.height() != target_size_dip) {
646 favicon =
647 skia::ImageOperations::Resize(favicon,
648 skia::ImageOperations::RESIZE_BEST,
649 target_size_dip,
650 target_size_dip);
653 bitmap = gfx::ConvertToJavaBitmap(&favicon);
655 return bitmap;
658 prerender::PrerenderManager* TabAndroid::GetPrerenderManager() const {
659 Profile* profile = GetProfile();
660 if (!profile)
661 return NULL;
662 return prerender::PrerenderManagerFactory::GetForProfile(profile);
665 // static
666 void TabAndroid::CreateHistoricalTabFromContents(WebContents* web_contents) {
667 DCHECK(web_contents);
669 TabRestoreService* service =
670 TabRestoreServiceFactory::GetForProfile(
671 Profile::FromBrowserContext(web_contents->GetBrowserContext()));
672 if (!service)
673 return;
675 // Exclude internal pages from being marked as recent when they are closed.
676 const GURL& tab_url = web_contents->GetURL();
677 if (tab_url.SchemeIs(content::kChromeUIScheme) ||
678 tab_url.SchemeIs(chrome::kChromeNativeScheme) ||
679 tab_url.SchemeIs(url::kAboutScheme)) {
680 return;
683 // TODO(jcivelli): is the index important?
684 service->CreateHistoricalTab(web_contents, -1);
687 void TabAndroid::CreateHistoricalTab(JNIEnv* env, jobject obj) {
688 TabAndroid::CreateHistoricalTabFromContents(web_contents());
691 void TabAndroid::UpdateTopControlsState(JNIEnv* env,
692 jobject obj,
693 jint constraints,
694 jint current,
695 jboolean animate) {
696 content::TopControlsState constraints_state =
697 static_cast<content::TopControlsState>(constraints);
698 content::TopControlsState current_state =
699 static_cast<content::TopControlsState>(current);
700 WebContents* sender = web_contents();
701 sender->Send(new ChromeViewMsg_UpdateTopControlsState(
702 sender->GetRoutingID(), constraints_state, current_state, animate));
705 void TabAndroid::SearchByImageInNewTabAsync(JNIEnv* env, jobject obj) {
706 content::RenderFrameHost* render_frame_host =
707 web_contents()->GetMainFrame();
708 render_frame_host->Send(
709 new ChromeViewMsg_RequestThumbnailForContextNode(
710 render_frame_host->GetRoutingID(),
711 kImageSearchThumbnailMinSize,
712 gfx::Size(kImageSearchThumbnailMaxWidth,
713 kImageSearchThumbnailMaxHeight)));
716 namespace {
718 class ChromeInterceptNavigationDelegate : public InterceptNavigationDelegate {
719 public:
720 ChromeInterceptNavigationDelegate(JNIEnv* env, jobject jdelegate)
721 : InterceptNavigationDelegate(env, jdelegate) {}
723 bool ShouldIgnoreNavigation(
724 const NavigationParams& navigation_params) override {
725 NavigationParams chrome_navigation_params(navigation_params);
726 chrome_navigation_params.url() =
727 GURL(net::EscapeExternalHandlerValue(navigation_params.url().spec()));
728 return InterceptNavigationDelegate::ShouldIgnoreNavigation(
729 chrome_navigation_params);
733 } // namespace
735 void TabAndroid::SetInterceptNavigationDelegate(JNIEnv* env, jobject obj,
736 jobject delegate) {
737 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
738 InterceptNavigationDelegate::Associate(
739 web_contents(),
740 make_scoped_ptr(new ChromeInterceptNavigationDelegate(env, delegate)));
743 static void Init(JNIEnv* env, jobject obj) {
744 TRACE_EVENT0("native", "TabAndroid::Init");
745 // This will automatically bind to the Java object and pass ownership there.
746 new TabAndroid(env, obj);
749 // static
750 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
751 return RegisterNativesImpl(env);
754 static void RecordStartupToCommitUma(JNIEnv* env, jclass jcaller) {
755 // Currently it takes about 2000ms to commit a navigation if the measurement
756 // begins very early in the browser start. How many buckets (b) are needed to
757 // explore the _typical_ values with granularity 100ms and a maximum duration
758 // of 1 minute?
759 // s^{n+1} / s^{n} = 2100 / 2000
760 // s = 1.05
761 // s^b = 60000
762 // b = ln(60000) / ln(1.05) ~= 225
763 UMA_HISTOGRAM_CUSTOM_TIMES("Startup.FirstCommitNavigationTime",
764 base::Time::Now() - chrome::android::GetMainEntryPointTime(),
765 base::TimeDelta::FromMilliseconds(1),
766 base::TimeDelta::FromMinutes(1),
767 225);