Use app list item shadow for app list folders.
[chromium-blink-merge.git] / chrome / browser / android / tab_android.cc
blob8eba5653bab76df6ffe54c0b695f6f34a2680ab4
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/metrics/histogram.h"
11 #include "base/trace_event/trace_event.h"
12 #include "cc/layers/layer.h"
13 #include "chrome/browser/android/chrome_web_contents_delegate_android.h"
14 #include "chrome/browser/android/compositor/tab_content_manager.h"
15 #include "chrome/browser/android/metrics/uma_utils.h"
16 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
17 #include "chrome/browser/bookmarks/chrome_bookmark_client.h"
18 #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
19 #include "chrome/browser/browser_about_handler.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
22 #include "chrome/browser/infobars/infobar_service.h"
23 #include "chrome/browser/prerender/prerender_contents.h"
24 #include "chrome/browser/prerender/prerender_manager.h"
25 #include "chrome/browser/prerender/prerender_manager_factory.h"
26 #include "chrome/browser/printing/print_view_manager_basic.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/profiles/profile_android.h"
29 #include "chrome/browser/search/instant_service.h"
30 #include "chrome/browser/search/instant_service_factory.h"
31 #include "chrome/browser/search/search.h"
32 #include "chrome/browser/sessions/session_tab_helper.h"
33 #include "chrome/browser/sessions/tab_restore_service.h"
34 #include "chrome/browser/sessions/tab_restore_service_factory.h"
35 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
36 #include "chrome/browser/tab_contents/tab_util.h"
37 #include "chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h"
38 #include "chrome/browser/ui/android/context_menu_helper.h"
39 #include "chrome/browser/ui/android/infobars/infobar_container_android.h"
40 #include "chrome/browser/ui/android/tab_model/tab_model.h"
41 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
42 #include "chrome/browser/ui/android/window_android_helper.h"
43 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
44 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
45 #include "chrome/browser/ui/search/search_tab_helper.h"
46 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
47 #include "chrome/browser/ui/tab_helpers.h"
48 #include "chrome/common/instant_types.h"
49 #include "chrome/common/render_messages.h"
50 #include "chrome/common/url_constants.h"
51 #include "components/bookmarks/browser/bookmark_model.h"
52 #include "components/bookmarks/browser/bookmark_node.h"
53 #include "components/bookmarks/browser/bookmark_utils.h"
54 #include "components/dom_distiller/core/url_utils.h"
55 #include "components/favicon/content/content_favicon_driver.h"
56 #include "components/infobars/core/infobar_container.h"
57 #include "components/navigation_interception/intercept_navigation_delegate.h"
58 #include "components/navigation_interception/navigation_params.h"
59 #include "components/url_fixer/url_fixer.h"
60 #include "content/public/browser/android/compositor.h"
61 #include "content/public/browser/android/content_view_core.h"
62 #include "content/public/browser/browser_thread.h"
63 #include "content/public/browser/interstitial_page.h"
64 #include "content/public/browser/navigation_entry.h"
65 #include "content/public/browser/notification_service.h"
66 #include "content/public/browser/render_frame_host.h"
67 #include "content/public/browser/render_process_host.h"
68 #include "content/public/browser/render_view_host.h"
69 #include "content/public/browser/user_metrics.h"
70 #include "content/public/browser/web_contents.h"
71 #include "content/public/common/top_controls_state.h"
72 #include "jni/Tab_jni.h"
73 #include "net/base/escape.h"
74 #include "skia/ext/image_operations.h"
75 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
76 #include "ui/base/resource/resource_bundle.h"
77 #include "ui/base/window_open_disposition.h"
78 #include "ui/gfx/android/device_display_info.h"
79 #include "ui/gfx/android/java_bitmap.h"
80 #include "ui/gfx/favicon_size.h"
81 #include "ui/gfx/image/image_skia.h"
83 using base::android::AttachCurrentThread;
84 using base::android::ConvertUTF8ToJavaString;
85 using base::android::ToJavaByteArray;
86 using content::BrowserThread;
87 using content::GlobalRequestID;
88 using content::NavigationController;
89 using content::WebContents;
90 using navigation_interception::InterceptNavigationDelegate;
91 using navigation_interception::NavigationParams;
93 namespace {
95 const int kImageSearchThumbnailMinSize = 300 * 300;
96 const int kImageSearchThumbnailMaxWidth = 600;
97 const int kImageSearchThumbnailMaxHeight = 600;
99 } // namespace
101 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
102 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
103 if (!core_tab_helper)
104 return NULL;
106 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
107 if (!core_delegate)
108 return NULL;
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 content_layer_(cc::Layer::Create(content::Compositor::LayerSettings())),
126 tab_content_manager_(NULL),
127 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
128 Java_Tab_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this));
131 TabAndroid::~TabAndroid() {
132 GetContentLayer()->RemoveAllChildren();
133 JNIEnv* env = base::android::AttachCurrentThread();
134 Java_Tab_clearNativePtr(env, weak_java_tab_.get(env).obj());
137 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() {
138 JNIEnv* env = base::android::AttachCurrentThread();
139 return weak_java_tab_.get(env);
142 scoped_refptr<cc::Layer> TabAndroid::GetContentLayer() const {
143 return content_layer_;
146 int TabAndroid::GetAndroidId() const {
147 JNIEnv* env = base::android::AttachCurrentThread();
148 return Java_Tab_getId(env, weak_java_tab_.get(env).obj());
151 int TabAndroid::GetSyncId() const {
152 JNIEnv* env = base::android::AttachCurrentThread();
153 return Java_Tab_getSyncId(env, weak_java_tab_.get(env).obj());
156 base::string16 TabAndroid::GetTitle() const {
157 JNIEnv* env = base::android::AttachCurrentThread();
158 return base::android::ConvertJavaStringToUTF16(
159 Java_Tab_getTitle(env, weak_java_tab_.get(env).obj()));
162 GURL TabAndroid::GetURL() const {
163 JNIEnv* env = base::android::AttachCurrentThread();
164 return GURL(base::android::ConvertJavaStringToUTF8(
165 Java_Tab_getUrl(env, weak_java_tab_.get(env).obj())));
168 bool TabAndroid::LoadIfNeeded() {
169 JNIEnv* env = base::android::AttachCurrentThread();
170 return Java_Tab_loadIfNeeded(env, weak_java_tab_.get(env).obj());
173 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
174 if (!web_contents())
175 return NULL;
177 return content::ContentViewCore::FromWebContents(web_contents());
180 Profile* TabAndroid::GetProfile() const {
181 if (!web_contents())
182 return NULL;
184 return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
187 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
188 return synced_tab_delegate_.get();
191 void TabAndroid::SetWindowSessionID(SessionID::id_type window_id) {
192 session_window_id_.set_id(window_id);
194 if (!web_contents())
195 return;
197 SessionTabHelper* session_tab_helper =
198 SessionTabHelper::FromWebContents(web_contents());
199 session_tab_helper->SetWindowID(session_window_id_);
202 void TabAndroid::SetSyncId(int sync_id) {
203 JNIEnv* env = base::android::AttachCurrentThread();
204 Java_Tab_setSyncId(env, weak_java_tab_.get(env).obj(), sync_id);
207 void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) {
208 DCHECK(params->source_contents == web_contents());
209 DCHECK(params->target_contents == NULL ||
210 params->target_contents == web_contents());
212 WindowOpenDisposition disposition = params->disposition;
213 const GURL& url = params->url;
215 if (disposition == NEW_POPUP ||
216 disposition == NEW_FOREGROUND_TAB ||
217 disposition == NEW_BACKGROUND_TAB ||
218 disposition == NEW_WINDOW ||
219 disposition == OFF_THE_RECORD) {
220 JNIEnv* env = AttachCurrentThread();
221 ScopedJavaLocalRef<jobject> jobj = weak_java_tab_.get(env);
222 ScopedJavaLocalRef<jstring> jurl(ConvertUTF8ToJavaString(env, url.spec()));
223 ScopedJavaLocalRef<jstring> jheaders(
224 ConvertUTF8ToJavaString(env, params->extra_headers));
225 ScopedJavaLocalRef<jbyteArray> jpost_data;
226 if (params->uses_post &&
227 params->browser_initiated_post_data.get() &&
228 params->browser_initiated_post_data.get()->size()) {
229 jpost_data = ToJavaByteArray(
230 env,
231 reinterpret_cast<const uint8*>(
232 params->browser_initiated_post_data.get()->front()),
233 params->browser_initiated_post_data.get()->size());
235 Java_Tab_openNewTab(env,
236 jobj.obj(),
237 jurl.obj(),
238 jheaders.obj(),
239 jpost_data.obj(),
240 disposition,
241 params->created_with_opener,
242 params->is_renderer_initiated);
243 } else {
244 NOTIMPLEMENTED();
248 bool TabAndroid::HasPrerenderedUrl(GURL gurl) {
249 prerender::PrerenderManager* prerender_manager = GetPrerenderManager();
250 if (!prerender_manager)
251 return false;
253 std::vector<content::WebContents*> contents =
254 prerender_manager->GetAllPrerenderingContents();
255 prerender::PrerenderContents* prerender_contents;
256 for (size_t i = 0; i < contents.size(); ++i) {
257 prerender_contents = prerender_manager->
258 GetPrerenderContents(contents.at(i));
259 if (prerender_contents->prerender_url() == gurl &&
260 prerender_contents->has_finished_loading()) {
261 return true;
264 return false;
267 void TabAndroid::MakeLoadURLParams(
268 chrome::NavigateParams* params,
269 NavigationController::LoadURLParams* load_url_params) {
270 load_url_params->referrer = params->referrer;
271 load_url_params->frame_tree_node_id = params->frame_tree_node_id;
272 load_url_params->redirect_chain = params->redirect_chain;
273 load_url_params->transition_type = params->transition;
274 load_url_params->extra_headers = params->extra_headers;
275 load_url_params->should_replace_current_entry =
276 params->should_replace_current_entry;
278 if (params->transferred_global_request_id != GlobalRequestID()) {
279 load_url_params->transferred_global_request_id =
280 params->transferred_global_request_id;
282 load_url_params->is_renderer_initiated = params->is_renderer_initiated;
284 // Only allows the browser-initiated navigation to use POST.
285 if (params->uses_post && !params->is_renderer_initiated) {
286 load_url_params->load_type =
287 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
288 load_url_params->browser_initiated_post_data =
289 params->browser_initiated_post_data;
293 void TabAndroid::SwapTabContents(content::WebContents* old_contents,
294 content::WebContents* new_contents,
295 bool did_start_load,
296 bool did_finish_load) {
297 JNIEnv* env = base::android::AttachCurrentThread();
298 Java_Tab_swapWebContents(
299 env,
300 weak_java_tab_.get(env).obj(),
301 new_contents->GetJavaWebContents().obj(),
302 did_start_load,
303 did_finish_load);
306 void TabAndroid::DefaultSearchProviderChanged(
307 bool google_base_url_domain_changed) {
308 // TODO(kmadhusu): Move this function definition to a common place and update
309 // BrowserInstantController::DefaultSearchProviderChanged to use the same.
310 if (!web_contents())
311 return;
313 InstantService* instant_service =
314 InstantServiceFactory::GetForProfile(GetProfile());
315 if (!instant_service)
316 return;
318 // Send new search URLs to the renderer.
319 content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost();
320 instant_service->SendSearchURLsToRenderer(rph);
322 // Reload the contents to ensure that it gets assigned to a non-previledged
323 // renderer.
324 if (!instant_service->IsInstantProcess(rph->GetID()))
325 return;
326 web_contents()->GetController().Reload(false);
328 // As the reload was not triggered by the user we don't want to close any
329 // infobars. We have to tell the InfoBarService after the reload, otherwise it
330 // would ignore this call when
331 // WebContentsObserver::DidStartNavigationToPendingEntry is invoked.
332 InfoBarService::FromWebContents(web_contents())->set_ignore_next_reload();
335 void TabAndroid::OnWebContentsInstantSupportDisabled(
336 const content::WebContents* contents) {
337 DCHECK(contents);
338 if (web_contents() != contents)
339 return;
341 JNIEnv* env = base::android::AttachCurrentThread();
342 Java_Tab_onWebContentsInstantSupportDisabled(env,
343 weak_java_tab_.get(env).obj());
346 void TabAndroid::Observe(int type,
347 const content::NotificationSource& source,
348 const content::NotificationDetails& details) {
349 JNIEnv* env = base::android::AttachCurrentThread();
350 switch (type) {
351 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: {
352 TabSpecificContentSettings* settings =
353 TabSpecificContentSettings::FromWebContents(web_contents());
354 if (!settings->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS)) {
355 // TODO(dfalcantara): Create an InfoBarDelegate to keep the
356 // PopupBlockedInfoBar logic native-side instead of straddling the JNI
357 // boundary.
358 int num_popups = 0;
359 PopupBlockerTabHelper* popup_blocker_helper =
360 PopupBlockerTabHelper::FromWebContents(web_contents());
361 if (popup_blocker_helper)
362 num_popups = popup_blocker_helper->GetBlockedPopupsCount();
364 if (num_popups > 0)
365 PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups);
367 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS);
369 break;
371 case content::NOTIFICATION_NAV_ENTRY_CHANGED:
372 Java_Tab_onNavEntryChanged(env, weak_java_tab_.get(env).obj());
373 break;
374 default:
375 NOTREACHED() << "Unexpected notification " << type;
376 break;
380 void TabAndroid::OnFaviconAvailable(const gfx::Image& image) {
381 SkBitmap favicon = image.AsImageSkia().GetRepresentation(1.0f).sk_bitmap();
382 if (favicon.empty())
383 return;
385 JNIEnv *env = base::android::AttachCurrentThread();
386 Java_Tab_onFaviconAvailable(env, weak_java_tab_.get(env).obj(),
387 gfx::ConvertToJavaBitmap(&favicon).obj());
390 void TabAndroid::OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
391 bool icon_url_changed) {
394 void TabAndroid::Destroy(JNIEnv* env, jobject obj) {
395 delete this;
398 void TabAndroid::InitWebContents(JNIEnv* env,
399 jobject obj,
400 jboolean incognito,
401 jobject jcontent_view_core,
402 jobject jweb_contents_delegate,
403 jobject jcontext_menu_populator) {
404 content::ContentViewCore* content_view_core =
405 content::ContentViewCore::GetNativeContentViewCore(env,
406 jcontent_view_core);
407 DCHECK(content_view_core);
408 DCHECK(content_view_core->GetWebContents());
410 web_contents_.reset(content_view_core->GetWebContents());
411 AttachTabHelpers(web_contents_.get());
413 SetWindowSessionID(session_window_id_.id());
415 session_tab_id_.set_id(
416 SessionTabHelper::FromWebContents(web_contents())->session_id().id());
417 ContextMenuHelper::FromWebContents(web_contents())->SetPopulator(
418 jcontext_menu_populator);
419 WindowAndroidHelper::FromWebContents(web_contents())->
420 SetWindowAndroid(content_view_core->GetWindowAndroid());
421 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this);
422 SearchTabHelper::FromWebContents(web_contents())->set_delegate(this);
423 web_contents_delegate_.reset(
424 new chrome::android::ChromeWebContentsDelegateAndroid(
425 env, jweb_contents_delegate));
426 web_contents_delegate_->LoadProgressChanged(web_contents(), 0);
427 web_contents()->SetDelegate(web_contents_delegate_.get());
429 notification_registrar_.Add(
430 this,
431 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
432 content::Source<content::WebContents>(web_contents()));
433 notification_registrar_.Add(
434 this,
435 content::NOTIFICATION_NAV_ENTRY_CHANGED,
436 content::Source<content::NavigationController>(
437 &web_contents()->GetController()));
439 favicon::FaviconDriver* favicon_driver =
440 favicon::ContentFaviconDriver::FromWebContents(web_contents_.get());
442 if (favicon_driver)
443 favicon_driver->AddObserver(this);
445 synced_tab_delegate_->SetWebContents(web_contents());
447 // Verify that the WebContents this tab represents matches the expected
448 // off the record state.
449 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito);
451 InstantService* instant_service =
452 InstantServiceFactory::GetForProfile(GetProfile());
453 if (instant_service)
454 instant_service->AddObserver(this);
456 content_layer_->InsertChild(content_view_core->GetLayer(), 0);
459 void TabAndroid::DestroyWebContents(JNIEnv* env,
460 jobject obj,
461 jboolean delete_native) {
462 DCHECK(web_contents());
464 content::ContentViewCore* content_view_core = GetContentViewCore();
465 if (content_view_core)
466 content_view_core->GetLayer()->RemoveFromParent();
468 notification_registrar_.Remove(
469 this,
470 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
471 content::Source<content::WebContents>(web_contents()));
472 notification_registrar_.Remove(
473 this,
474 content::NOTIFICATION_NAV_ENTRY_CHANGED,
475 content::Source<content::NavigationController>(
476 &web_contents()->GetController()));
478 favicon::FaviconDriver* favicon_driver =
479 favicon::ContentFaviconDriver::FromWebContents(web_contents_.get());
481 if (favicon_driver)
482 favicon_driver->RemoveObserver(this);
484 InstantService* instant_service =
485 InstantServiceFactory::GetForProfile(GetProfile());
486 if (instant_service)
487 instant_service->RemoveObserver(this);
489 web_contents()->SetDelegate(NULL);
491 if (delete_native) {
492 // Terminate the renderer process if this is the last tab.
493 // If there's no unload listener, FastShutdownForPageCount kills the
494 // renderer process. Otherwise, we go with the slow path where renderer
495 // process shuts down itself when ref count becomes 0.
496 // This helps the render process exit quickly which avoids some issues
497 // during shutdown. See https://codereview.chromium.org/146693011/
498 // and http://crbug.com/338709 for details.
499 content::RenderProcessHost* process =
500 web_contents()->GetRenderProcessHost();
501 if (process)
502 process->FastShutdownForPageCount(1);
504 web_contents_.reset();
505 synced_tab_delegate_->ResetWebContents();
506 } else {
507 // Release the WebContents so it does not get deleted by the scoped_ptr.
508 ignore_result(web_contents_.release());
512 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid(
513 JNIEnv* env,
514 jobject obj) {
515 Profile* profile = GetProfile();
516 if (!profile)
517 return base::android::ScopedJavaLocalRef<jobject>();
518 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
519 if (!profile_android)
520 return base::android::ScopedJavaLocalRef<jobject>();
522 return profile_android->GetJavaObject();
525 TabAndroid::TabLoadStatus TabAndroid::LoadUrl(JNIEnv* env,
526 jobject obj,
527 jstring url,
528 jstring j_extra_headers,
529 jbyteArray j_post_data,
530 jint page_transition,
531 jstring j_referrer_url,
532 jint referrer_policy,
533 jboolean is_renderer_initiated,
534 jlong intent_received_timestamp) {
535 if (!web_contents())
536 return PAGE_LOAD_FAILED;
538 GURL gurl(base::android::ConvertJavaStringToUTF8(env, url));
539 if (gurl.is_empty())
540 return PAGE_LOAD_FAILED;
542 // If the page was prerendered, use it.
543 // Note in incognito mode, we don't have a PrerenderManager.
545 prerender::PrerenderManager* prerender_manager =
546 prerender::PrerenderManagerFactory::GetForProfile(GetProfile());
547 if (prerender_manager) {
548 bool prefetched_page_loaded = HasPrerenderedUrl(gurl);
549 // Getting the load status before MaybeUsePrerenderedPage() b/c it resets.
550 chrome::NavigateParams params(NULL, web_contents());
551 InstantSearchPrerenderer* prerenderer =
552 InstantSearchPrerenderer::GetForProfile(GetProfile());
553 if (prerenderer) {
554 const base::string16& search_terms =
555 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl);
556 if (!search_terms.empty() &&
557 prerenderer->CanCommitQuery(web_contents_.get(), search_terms)) {
558 EmbeddedSearchRequestParams request_params(gurl);
559 prerenderer->Commit(search_terms, request_params);
561 if (prerenderer->UsePrerenderedPage(gurl, &params))
562 return FULL_PRERENDERED_PAGE_LOAD;
564 prerenderer->Cancel();
566 if (prerender_manager->MaybeUsePrerenderedPage(gurl, &params)) {
567 return prefetched_page_loaded ?
568 FULL_PRERENDERED_PAGE_LOAD : PARTIAL_PRERENDERED_PAGE_LOAD;
572 GURL fixed_url(
573 url_fixer::FixupURL(gurl.possibly_invalid_spec(), std::string()));
574 if (!fixed_url.is_valid())
575 return PAGE_LOAD_FAILED;
577 if (!HandleNonNavigationAboutURL(fixed_url)) {
578 // Record UMA "ShowHistory" here. That way it'll pick up both user
579 // typing chrome://history as well as selecting from the drop down menu.
580 if (fixed_url.spec() == chrome::kChromeUIHistoryURL) {
581 content::RecordAction(base::UserMetricsAction("ShowHistory"));
584 content::NavigationController::LoadURLParams load_params(fixed_url);
585 if (j_extra_headers) {
586 load_params.extra_headers = base::android::ConvertJavaStringToUTF8(
587 env,
588 j_extra_headers);
590 if (j_post_data) {
591 load_params.load_type =
592 content::NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
593 std::vector<uint8> post_data;
594 base::android::JavaByteArrayToByteVector(env, j_post_data, &post_data);
595 load_params.browser_initiated_post_data =
596 base::RefCountedBytes::TakeVector(&post_data);
598 load_params.transition_type =
599 ui::PageTransitionFromInt(page_transition);
600 if (j_referrer_url) {
601 load_params.referrer = content::Referrer(
602 GURL(base::android::ConvertJavaStringToUTF8(env, j_referrer_url)),
603 static_cast<blink::WebReferrerPolicy>(referrer_policy));
605 const base::string16 search_terms =
606 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl);
607 SearchTabHelper* search_tab_helper =
608 SearchTabHelper::FromWebContents(web_contents_.get());
609 if (!search_terms.empty() && search_tab_helper &&
610 search_tab_helper->SupportsInstant()) {
611 EmbeddedSearchRequestParams request_params(gurl);
612 search_tab_helper->Submit(search_terms, request_params);
613 return DEFAULT_PAGE_LOAD;
615 load_params.is_renderer_initiated = is_renderer_initiated;
616 load_params.intent_received_timestamp = intent_received_timestamp;
617 web_contents()->GetController().LoadURLWithParams(load_params);
619 return DEFAULT_PAGE_LOAD;
622 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env,
623 jobject obj,
624 jstring jurl,
625 jstring jtitle) {
626 DCHECK(web_contents());
628 base::string16 title;
629 if (jtitle)
630 title = base::android::ConvertJavaStringToUTF16(env, jtitle);
632 std::string url;
633 if (jurl)
634 url = base::android::ConvertJavaStringToUTF8(env, jurl);
636 content::NavigationEntry* entry =
637 web_contents()->GetController().GetVisibleEntry();
638 if (entry && url == entry->GetVirtualURL().spec())
639 entry->SetTitle(title);
642 bool TabAndroid::Print(JNIEnv* env, jobject obj) {
643 if (!web_contents())
644 return false;
646 printing::PrintViewManagerBasic::CreateForWebContents(web_contents());
647 printing::PrintViewManagerBasic* print_view_manager =
648 printing::PrintViewManagerBasic::FromWebContents(web_contents());
649 if (print_view_manager == NULL)
650 return false;
652 print_view_manager->PrintNow();
653 return true;
656 void TabAndroid::SetPendingPrint() {
657 JNIEnv* env = base::android::AttachCurrentThread();
658 Java_Tab_setPendingPrint(env, weak_java_tab_.get(env).obj());
661 ScopedJavaLocalRef<jobject> TabAndroid::GetFavicon(JNIEnv* env,
662 jobject obj) {
664 ScopedJavaLocalRef<jobject> bitmap;
665 favicon::FaviconDriver* favicon_driver =
666 favicon::ContentFaviconDriver::FromWebContents(web_contents_.get());
668 if (!favicon_driver)
669 return bitmap;
671 // Always return the default favicon in Android.
672 SkBitmap favicon = favicon_driver->GetFavicon().AsBitmap();
673 if (!favicon.empty()) {
674 gfx::DeviceDisplayInfo device_info;
675 const float device_scale_factor = device_info.GetDIPScale();
676 int target_size_dip = device_scale_factor * gfx::kFaviconSize;
677 if (favicon.width() != target_size_dip ||
678 favicon.height() != target_size_dip) {
679 favicon =
680 skia::ImageOperations::Resize(favicon,
681 skia::ImageOperations::RESIZE_BEST,
682 target_size_dip,
683 target_size_dip);
686 bitmap = gfx::ConvertToJavaBitmap(&favicon);
688 return bitmap;
691 prerender::PrerenderManager* TabAndroid::GetPrerenderManager() const {
692 Profile* profile = GetProfile();
693 if (!profile)
694 return NULL;
695 return prerender::PrerenderManagerFactory::GetForProfile(profile);
698 // static
699 void TabAndroid::CreateHistoricalTabFromContents(WebContents* web_contents) {
700 DCHECK(web_contents);
702 TabRestoreService* service =
703 TabRestoreServiceFactory::GetForProfile(
704 Profile::FromBrowserContext(web_contents->GetBrowserContext()));
705 if (!service)
706 return;
708 // Exclude internal pages from being marked as recent when they are closed.
709 const GURL& tab_url = web_contents->GetURL();
710 if (tab_url.SchemeIs(content::kChromeUIScheme) ||
711 tab_url.SchemeIs(chrome::kChromeNativeScheme) ||
712 tab_url.SchemeIs(url::kAboutScheme)) {
713 return;
716 // TODO(jcivelli): is the index important?
717 service->CreateHistoricalTab(web_contents, -1);
720 void TabAndroid::CreateHistoricalTab(JNIEnv* env, jobject obj) {
721 TabAndroid::CreateHistoricalTabFromContents(web_contents());
724 void TabAndroid::UpdateTopControlsState(JNIEnv* env,
725 jobject obj,
726 jint constraints,
727 jint current,
728 jboolean animate) {
729 content::TopControlsState constraints_state =
730 static_cast<content::TopControlsState>(constraints);
731 content::TopControlsState current_state =
732 static_cast<content::TopControlsState>(current);
733 WebContents* sender = web_contents();
734 sender->Send(new ChromeViewMsg_UpdateTopControlsState(
735 sender->GetRoutingID(), constraints_state, current_state, animate));
737 if (sender->ShowingInterstitialPage()) {
738 content::RenderViewHost* interstitial_view_host =
739 sender->GetInterstitialPage()->GetMainFrame()->GetRenderViewHost();
740 interstitial_view_host->Send(new ChromeViewMsg_UpdateTopControlsState(
741 interstitial_view_host->GetRoutingID(), constraints_state,
742 current_state, animate));
746 void TabAndroid::ShowOriginalImage(JNIEnv* env, jobject obj) {
747 content::RenderFrameHost* render_frame_host = web_contents()->GetMainFrame();
748 render_frame_host->Send(new ChromeViewMsg_RequestReloadImageForContextNode(
749 render_frame_host->GetRoutingID()));
752 void TabAndroid::SearchByImageInNewTabAsync(JNIEnv* env, jobject obj) {
753 content::RenderFrameHost* render_frame_host =
754 web_contents()->GetMainFrame();
755 render_frame_host->Send(
756 new ChromeViewMsg_RequestThumbnailForContextNode(
757 render_frame_host->GetRoutingID(),
758 kImageSearchThumbnailMinSize,
759 gfx::Size(kImageSearchThumbnailMaxWidth,
760 kImageSearchThumbnailMaxHeight)));
763 jlong TabAndroid::GetBookmarkId(JNIEnv* env,
764 jobject obj,
765 jboolean only_editable) {
766 const GURL& url = dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(
767 web_contents()->GetURL());
768 Profile* profile = GetProfile();
770 // Get all the nodes for |url| and sort them by date added.
771 std::vector<const bookmarks::BookmarkNode*> nodes;
772 ChromeBookmarkClient* client =
773 ChromeBookmarkClientFactory::GetForProfile(profile);
774 bookmarks::BookmarkModel* model =
775 BookmarkModelFactory::GetForProfile(profile);
776 model->GetNodesByURL(url, &nodes);
777 std::sort(nodes.begin(), nodes.end(), &bookmarks::MoreRecentlyAdded);
779 // Return the first node matching the search criteria.
780 for (size_t i = 0; i < nodes.size(); ++i) {
781 if (only_editable && !client->CanBeEditedByUser(nodes[i]))
782 continue;
783 return nodes[i]->id();
786 return -1;
789 bool TabAndroid::HasPrerenderedUrl(JNIEnv* env, jobject obj, jstring url) {
790 GURL gurl(base::android::ConvertJavaStringToUTF8(env, url));
791 return HasPrerenderedUrl(gurl);
794 namespace {
796 class ChromeInterceptNavigationDelegate : public InterceptNavigationDelegate {
797 public:
798 ChromeInterceptNavigationDelegate(JNIEnv* env, jobject jdelegate)
799 : InterceptNavigationDelegate(env, jdelegate) {}
801 bool ShouldIgnoreNavigation(
802 const NavigationParams& navigation_params) override {
803 NavigationParams chrome_navigation_params(navigation_params);
804 chrome_navigation_params.url() =
805 GURL(net::EscapeExternalHandlerValue(navigation_params.url().spec()));
806 return InterceptNavigationDelegate::ShouldIgnoreNavigation(
807 chrome_navigation_params);
811 } // namespace
813 void TabAndroid::SetInterceptNavigationDelegate(JNIEnv* env, jobject obj,
814 jobject delegate) {
815 DCHECK_CURRENTLY_ON(BrowserThread::UI);
816 InterceptNavigationDelegate::Associate(
817 web_contents(),
818 make_scoped_ptr(new ChromeInterceptNavigationDelegate(env, delegate)));
821 void TabAndroid::AttachToTabContentManager(JNIEnv* env,
822 jobject obj,
823 jobject jtab_content_manager) {
824 chrome::android::TabContentManager* tab_content_manager =
825 chrome::android::TabContentManager::FromJavaObject(jtab_content_manager);
826 if (tab_content_manager == tab_content_manager_)
827 return;
829 if (tab_content_manager_)
830 tab_content_manager_->DetachLiveLayer(GetAndroidId(), GetContentLayer());
831 tab_content_manager_ = tab_content_manager;
832 if (tab_content_manager_)
833 tab_content_manager_->AttachLiveLayer(GetAndroidId(), GetContentLayer());
836 void TabAndroid::AttachOverlayContentViewCore(JNIEnv* env,
837 jobject obj,
838 jobject jcontent_view_core,
839 jboolean visible) {
840 content::ContentViewCore* content_view_core =
841 content::ContentViewCore::GetNativeContentViewCore(env,
842 jcontent_view_core);
843 DCHECK(content_view_core);
845 content_view_core->GetLayer()->SetHideLayerAndSubtree(!visible);
846 content_layer_->AddChild(content_view_core->GetLayer());
849 void TabAndroid::DetachOverlayContentViewCore(JNIEnv* env,
850 jobject obj,
851 jobject jcontent_view_core) {
852 content::ContentViewCore* content_view_core =
853 content::ContentViewCore::GetNativeContentViewCore(env,
854 jcontent_view_core);
855 DCHECK(content_view_core);
857 if (content_view_core->GetLayer()->parent() == content_layer_)
858 content_view_core->GetLayer()->RemoveFromParent();
861 static void Init(JNIEnv* env, jobject obj) {
862 TRACE_EVENT0("native", "TabAndroid::Init");
863 // This will automatically bind to the Java object and pass ownership there.
864 new TabAndroid(env, obj);
867 // static
868 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
869 return RegisterNativesImpl(env);
872 static void RecordStartupToCommitUma(JNIEnv* env, jclass jcaller) {
873 // Currently it takes about 2000ms to commit a navigation if the measurement
874 // begins very early in the browser start. How many buckets (b) are needed to
875 // explore the _typical_ values with granularity 100ms and a maximum duration
876 // of 1 minute?
877 // s^{n+1} / s^{n} = 2100 / 2000
878 // s = 1.05
879 // s^b = 60000
880 // b = ln(60000) / ln(1.05) ~= 225
881 UMA_HISTOGRAM_CUSTOM_TIMES("Startup.FirstCommitNavigationTime",
882 base::Time::Now() - chrome::android::GetMainEntryPointTime(),
883 base::TimeDelta::FromMilliseconds(1),
884 base::TimeDelta::FromMinutes(1),
885 225);