Add more checks to investigate SupervisedUserPrefStore crash at startup.
[chromium-blink-merge.git] / chrome / browser / android / tab_android.cc
blob0ddf50d3c830aac0bf5772caf10b135a8e380527
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/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/favicon/favicon_tab_helper.h"
23 #include "chrome/browser/infobars/infobar_service.h"
24 #include "chrome/browser/prerender/prerender_contents.h"
25 #include "chrome/browser/prerender/prerender_manager.h"
26 #include "chrome/browser/prerender/prerender_manager_factory.h"
27 #include "chrome/browser/printing/print_view_manager_basic.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/profiles/profile_android.h"
30 #include "chrome/browser/search/instant_service.h"
31 #include "chrome/browser/search/instant_service_factory.h"
32 #include "chrome/browser/search/search.h"
33 #include "chrome/browser/sessions/session_tab_helper.h"
34 #include "chrome/browser/sessions/tab_restore_service.h"
35 #include "chrome/browser/sessions/tab_restore_service_factory.h"
36 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
37 #include "chrome/browser/tab_contents/tab_util.h"
38 #include "chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h"
39 #include "chrome/browser/ui/android/context_menu_helper.h"
40 #include "chrome/browser/ui/android/infobars/infobar_container_android.h"
41 #include "chrome/browser/ui/android/tab_model/tab_model.h"
42 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
43 #include "chrome/browser/ui/android/window_android_helper.h"
44 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
45 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
46 #include "chrome/browser/ui/search/search_tab_helper.h"
47 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
48 #include "chrome/browser/ui/tab_helpers.h"
49 #include "chrome/common/instant_types.h"
50 #include "chrome/common/render_messages.h"
51 #include "chrome/common/url_constants.h"
52 #include "components/bookmarks/browser/bookmark_model.h"
53 #include "components/bookmarks/browser/bookmark_node.h"
54 #include "components/bookmarks/browser/bookmark_utils.h"
55 #include "components/dom_distiller/core/url_utils.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/content_view_core.h"
61 #include "content/public/browser/browser_thread.h"
62 #include "content/public/browser/navigation_entry.h"
63 #include "content/public/browser/notification_service.h"
64 #include "content/public/browser/render_frame_host.h"
65 #include "content/public/browser/render_process_host.h"
66 #include "content/public/browser/user_metrics.h"
67 #include "content/public/browser/web_contents.h"
68 #include "content/public/common/top_controls_state.h"
69 #include "jni/Tab_jni.h"
70 #include "net/base/escape.h"
71 #include "skia/ext/image_operations.h"
72 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
73 #include "ui/base/resource/resource_bundle.h"
74 #include "ui/base/window_open_disposition.h"
75 #include "ui/gfx/android/device_display_info.h"
76 #include "ui/gfx/android/java_bitmap.h"
77 #include "ui/gfx/favicon_size.h"
78 #include "ui/gfx/image/image_skia.h"
80 using base::android::AttachCurrentThread;
81 using base::android::ConvertUTF8ToJavaString;
82 using base::android::ToJavaByteArray;
83 using content::BrowserThread;
84 using content::GlobalRequestID;
85 using content::NavigationController;
86 using content::WebContents;
87 using navigation_interception::InterceptNavigationDelegate;
88 using navigation_interception::NavigationParams;
90 namespace {
92 const int kImageSearchThumbnailMinSize = 300 * 300;
93 const int kImageSearchThumbnailMaxWidth = 600;
94 const int kImageSearchThumbnailMaxHeight = 600;
96 } // namespace
98 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
99 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
100 if (!core_tab_helper)
101 return NULL;
103 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
104 if (!core_delegate)
105 return NULL;
107 return static_cast<TabAndroid*>(core_delegate);
110 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
111 return reinterpret_cast<TabAndroid*>(Java_Tab_getNativePtr(env, obj));
114 void TabAndroid::AttachTabHelpers(content::WebContents* web_contents) {
115 DCHECK(web_contents);
117 TabHelpers::AttachTabHelpers(web_contents);
120 TabAndroid::TabAndroid(JNIEnv* env, jobject obj)
121 : weak_java_tab_(env, obj),
122 content_layer_(cc::Layer::Create()),
123 tab_content_manager_(NULL),
124 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
125 Java_Tab_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this));
128 TabAndroid::~TabAndroid() {
129 GetContentLayer()->RemoveAllChildren();
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 scoped_refptr<cc::Layer> TabAndroid::GetContentLayer() const {
140 return content_layer_;
143 int TabAndroid::GetAndroidId() const {
144 JNIEnv* env = base::android::AttachCurrentThread();
145 return Java_Tab_getId(env, weak_java_tab_.get(env).obj());
148 int TabAndroid::GetSyncId() const {
149 JNIEnv* env = base::android::AttachCurrentThread();
150 return Java_Tab_getSyncId(env, weak_java_tab_.get(env).obj());
153 base::string16 TabAndroid::GetTitle() const {
154 JNIEnv* env = base::android::AttachCurrentThread();
155 return base::android::ConvertJavaStringToUTF16(
156 Java_Tab_getTitle(env, weak_java_tab_.get(env).obj()));
159 GURL TabAndroid::GetURL() const {
160 JNIEnv* env = base::android::AttachCurrentThread();
161 return GURL(base::android::ConvertJavaStringToUTF8(
162 Java_Tab_getUrl(env, weak_java_tab_.get(env).obj())));
165 bool TabAndroid::LoadIfNeeded() {
166 JNIEnv* env = base::android::AttachCurrentThread();
167 return Java_Tab_loadIfNeeded(env, weak_java_tab_.get(env).obj());
170 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
171 if (!web_contents())
172 return NULL;
174 return content::ContentViewCore::FromWebContents(web_contents());
177 Profile* TabAndroid::GetProfile() const {
178 if (!web_contents())
179 return NULL;
181 return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
184 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
185 return synced_tab_delegate_.get();
188 void TabAndroid::SetWindowSessionID(SessionID::id_type window_id) {
189 session_window_id_.set_id(window_id);
191 if (!web_contents())
192 return;
194 SessionTabHelper* session_tab_helper =
195 SessionTabHelper::FromWebContents(web_contents());
196 session_tab_helper->SetWindowID(session_window_id_);
199 void TabAndroid::SetSyncId(int sync_id) {
200 JNIEnv* env = base::android::AttachCurrentThread();
201 Java_Tab_setSyncId(env, weak_java_tab_.get(env).obj(), sync_id);
204 void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) {
205 DCHECK(params->source_contents == web_contents());
206 DCHECK(params->target_contents == NULL ||
207 params->target_contents == web_contents());
209 WindowOpenDisposition disposition = params->disposition;
210 const GURL& url = params->url;
212 if (disposition == NEW_POPUP ||
213 disposition == NEW_FOREGROUND_TAB ||
214 disposition == NEW_BACKGROUND_TAB ||
215 disposition == NEW_WINDOW ||
216 disposition == OFF_THE_RECORD) {
217 JNIEnv* env = AttachCurrentThread();
218 ScopedJavaLocalRef<jobject> jobj = weak_java_tab_.get(env);
219 ScopedJavaLocalRef<jstring> jurl(ConvertUTF8ToJavaString(env, url.spec()));
220 ScopedJavaLocalRef<jstring> jheaders(
221 ConvertUTF8ToJavaString(env, params->extra_headers));
222 ScopedJavaLocalRef<jbyteArray> jpost_data;
223 if (params->uses_post &&
224 params->browser_initiated_post_data.get() &&
225 params->browser_initiated_post_data.get()->size()) {
226 jpost_data = ToJavaByteArray(
227 env,
228 reinterpret_cast<const uint8*>(
229 params->browser_initiated_post_data.get()->front()),
230 params->browser_initiated_post_data.get()->size());
232 Java_Tab_openNewTab(env,
233 jobj.obj(),
234 jurl.obj(),
235 jheaders.obj(),
236 jpost_data.obj(),
237 disposition,
238 params->should_set_opener,
239 params->is_renderer_initiated);
240 } else {
241 NOTIMPLEMENTED();
245 bool TabAndroid::HasPrerenderedUrl(GURL gurl) {
246 prerender::PrerenderManager* prerender_manager = GetPrerenderManager();
247 if (!prerender_manager)
248 return false;
250 std::vector<content::WebContents*> contents =
251 prerender_manager->GetAllPrerenderingContents();
252 prerender::PrerenderContents* prerender_contents;
253 for (size_t i = 0; i < contents.size(); ++i) {
254 prerender_contents = prerender_manager->
255 GetPrerenderContents(contents.at(i));
256 if (prerender_contents->prerender_url() == gurl &&
257 prerender_contents->has_finished_loading()) {
258 return true;
261 return false;
264 void TabAndroid::MakeLoadURLParams(
265 chrome::NavigateParams* params,
266 NavigationController::LoadURLParams* load_url_params) {
267 load_url_params->referrer = params->referrer;
268 load_url_params->frame_tree_node_id = params->frame_tree_node_id;
269 load_url_params->redirect_chain = params->redirect_chain;
270 load_url_params->transition_type = params->transition;
271 load_url_params->extra_headers = params->extra_headers;
272 load_url_params->should_replace_current_entry =
273 params->should_replace_current_entry;
275 if (params->transferred_global_request_id != GlobalRequestID()) {
276 load_url_params->transferred_global_request_id =
277 params->transferred_global_request_id;
279 load_url_params->is_renderer_initiated = params->is_renderer_initiated;
281 // Only allows the browser-initiated navigation to use POST.
282 if (params->uses_post && !params->is_renderer_initiated) {
283 load_url_params->load_type =
284 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
285 load_url_params->browser_initiated_post_data =
286 params->browser_initiated_post_data;
290 void TabAndroid::SwapTabContents(content::WebContents* old_contents,
291 content::WebContents* new_contents,
292 bool did_start_load,
293 bool did_finish_load) {
294 JNIEnv* env = base::android::AttachCurrentThread();
296 // We need to notify the native InfobarContainer so infobars can be swapped.
297 InfoBarContainerAndroid* infobar_container =
298 reinterpret_cast<InfoBarContainerAndroid*>(
299 Java_Tab_getNativeInfoBarContainer(
300 env,
301 weak_java_tab_.get(env).obj()));
302 InfoBarService* new_infobar_service =
303 new_contents ? InfoBarService::FromWebContents(new_contents) : NULL;
304 infobar_container->ChangeInfoBarManager(new_infobar_service);
306 Java_Tab_swapWebContents(
307 env,
308 weak_java_tab_.get(env).obj(),
309 new_contents->GetJavaWebContents().obj(),
310 did_start_load,
311 did_finish_load);
314 void TabAndroid::DefaultSearchProviderChanged(
315 bool google_base_url_domain_changed) {
316 // TODO(kmadhusu): Move this function definition to a common place and update
317 // BrowserInstantController::DefaultSearchProviderChanged to use the same.
318 if (!web_contents())
319 return;
321 InstantService* instant_service =
322 InstantServiceFactory::GetForProfile(GetProfile());
323 if (!instant_service)
324 return;
326 // Send new search URLs to the renderer.
327 content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost();
328 instant_service->SendSearchURLsToRenderer(rph);
330 // Reload the contents to ensure that it gets assigned to a non-previledged
331 // renderer.
332 if (!instant_service->IsInstantProcess(rph->GetID()))
333 return;
334 web_contents()->GetController().Reload(false);
336 // As the reload was not triggered by the user we don't want to close any
337 // infobars. We have to tell the InfoBarService after the reload, otherwise it
338 // would ignore this call when
339 // WebContentsObserver::DidStartNavigationToPendingEntry is invoked.
340 InfoBarService::FromWebContents(web_contents())->set_ignore_next_reload();
343 void TabAndroid::OnWebContentsInstantSupportDisabled(
344 const content::WebContents* contents) {
345 DCHECK(contents);
346 if (web_contents() != contents)
347 return;
349 JNIEnv* env = base::android::AttachCurrentThread();
350 Java_Tab_onWebContentsInstantSupportDisabled(env,
351 weak_java_tab_.get(env).obj());
354 void TabAndroid::Observe(int type,
355 const content::NotificationSource& source,
356 const content::NotificationDetails& details) {
357 JNIEnv* env = base::android::AttachCurrentThread();
358 switch (type) {
359 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: {
360 TabSpecificContentSettings* settings =
361 TabSpecificContentSettings::FromWebContents(web_contents());
362 if (!settings->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS)) {
363 // TODO(dfalcantara): Create an InfoBarDelegate to keep the
364 // PopupBlockedInfoBar logic native-side instead of straddling the JNI
365 // boundary.
366 int num_popups = 0;
367 PopupBlockerTabHelper* popup_blocker_helper =
368 PopupBlockerTabHelper::FromWebContents(web_contents());
369 if (popup_blocker_helper)
370 num_popups = popup_blocker_helper->GetBlockedPopupsCount();
372 if (num_popups > 0)
373 PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups);
375 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS);
377 break;
379 case content::NOTIFICATION_NAV_ENTRY_CHANGED:
380 Java_Tab_onNavEntryChanged(env, weak_java_tab_.get(env).obj());
381 break;
382 default:
383 NOTREACHED() << "Unexpected notification " << type;
384 break;
388 void TabAndroid::OnFaviconAvailable(const gfx::Image& image) {
389 SkBitmap favicon = image.AsImageSkia().GetRepresentation(1.0f).sk_bitmap();
390 if (favicon.empty())
391 return;
393 JNIEnv *env = base::android::AttachCurrentThread();
394 Java_Tab_onFaviconAvailable(env, weak_java_tab_.get(env).obj(),
395 gfx::ConvertToJavaBitmap(&favicon).obj());
398 void TabAndroid::Destroy(JNIEnv* env, jobject obj) {
399 delete this;
402 void TabAndroid::InitWebContents(JNIEnv* env,
403 jobject obj,
404 jboolean incognito,
405 jobject jcontent_view_core,
406 jobject jweb_contents_delegate,
407 jobject jcontext_menu_populator) {
408 content::ContentViewCore* content_view_core =
409 content::ContentViewCore::GetNativeContentViewCore(env,
410 jcontent_view_core);
411 DCHECK(content_view_core);
412 DCHECK(content_view_core->GetWebContents());
414 web_contents_.reset(content_view_core->GetWebContents());
415 AttachTabHelpers(web_contents_.get());
417 SetWindowSessionID(session_window_id_.id());
419 session_tab_id_.set_id(
420 SessionTabHelper::FromWebContents(web_contents())->session_id().id());
421 ContextMenuHelper::FromWebContents(web_contents())->SetPopulator(
422 jcontext_menu_populator);
423 WindowAndroidHelper::FromWebContents(web_contents())->
424 SetWindowAndroid(content_view_core->GetWindowAndroid());
425 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this);
426 SearchTabHelper::FromWebContents(web_contents())->set_delegate(this);
427 web_contents_delegate_.reset(
428 new chrome::android::ChromeWebContentsDelegateAndroid(
429 env, jweb_contents_delegate));
430 web_contents_delegate_->LoadProgressChanged(web_contents(), 0);
431 web_contents()->SetDelegate(web_contents_delegate_.get());
433 notification_registrar_.Add(
434 this,
435 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
436 content::Source<content::WebContents>(web_contents()));
437 notification_registrar_.Add(
438 this,
439 content::NOTIFICATION_NAV_ENTRY_CHANGED,
440 content::Source<content::NavigationController>(
441 &web_contents()->GetController()));
443 FaviconTabHelper* favicon_tab_helper =
444 FaviconTabHelper::FromWebContents(web_contents_.get());
446 if (favicon_tab_helper)
447 favicon_tab_helper->AddObserver(this);
449 synced_tab_delegate_->SetWebContents(web_contents());
451 // Verify that the WebContents this tab represents matches the expected
452 // off the record state.
453 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito);
455 InstantService* instant_service =
456 InstantServiceFactory::GetForProfile(GetProfile());
457 if (instant_service)
458 instant_service->AddObserver(this);
460 content_layer_->InsertChild(content_view_core->GetLayer(), 0);
463 void TabAndroid::DestroyWebContents(JNIEnv* env,
464 jobject obj,
465 jboolean delete_native) {
466 DCHECK(web_contents());
468 content::ContentViewCore* content_view_core = GetContentViewCore();
469 if (content_view_core)
470 content_view_core->GetLayer()->RemoveFromParent();
472 notification_registrar_.Remove(
473 this,
474 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
475 content::Source<content::WebContents>(web_contents()));
476 notification_registrar_.Remove(
477 this,
478 content::NOTIFICATION_NAV_ENTRY_CHANGED,
479 content::Source<content::NavigationController>(
480 &web_contents()->GetController()));
482 FaviconTabHelper* favicon_tab_helper =
483 FaviconTabHelper::FromWebContents(web_contents_.get());
485 if (favicon_tab_helper)
486 favicon_tab_helper->RemoveObserver(this);
488 InstantService* instant_service =
489 InstantServiceFactory::GetForProfile(GetProfile());
490 if (instant_service)
491 instant_service->RemoveObserver(this);
493 web_contents()->SetDelegate(NULL);
495 if (delete_native) {
496 web_contents_.reset();
497 synced_tab_delegate_->ResetWebContents();
498 } else {
499 // Release the WebContents so it does not get deleted by the scoped_ptr.
500 ignore_result(web_contents_.release());
504 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid(
505 JNIEnv* env,
506 jobject obj) {
507 Profile* profile = GetProfile();
508 if (!profile)
509 return base::android::ScopedJavaLocalRef<jobject>();
510 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
511 if (!profile_android)
512 return base::android::ScopedJavaLocalRef<jobject>();
514 return profile_android->GetJavaObject();
517 TabAndroid::TabLoadStatus TabAndroid::LoadUrl(JNIEnv* env,
518 jobject obj,
519 jstring url,
520 jstring j_extra_headers,
521 jbyteArray j_post_data,
522 jint page_transition,
523 jstring j_referrer_url,
524 jint referrer_policy,
525 jboolean is_renderer_initiated,
526 jlong intent_received_timestamp) {
527 if (!web_contents())
528 return PAGE_LOAD_FAILED;
530 GURL gurl(base::android::ConvertJavaStringToUTF8(env, url));
531 if (gurl.is_empty())
532 return PAGE_LOAD_FAILED;
534 // If the page was prerendered, use it.
535 // Note in incognito mode, we don't have a PrerenderManager.
537 prerender::PrerenderManager* prerender_manager =
538 prerender::PrerenderManagerFactory::GetForProfile(GetProfile());
539 if (prerender_manager) {
540 bool prefetched_page_loaded = HasPrerenderedUrl(gurl);
541 // Getting the load status before MaybeUsePrerenderedPage() b/c it resets.
542 chrome::NavigateParams params(NULL, web_contents());
543 InstantSearchPrerenderer* prerenderer =
544 InstantSearchPrerenderer::GetForProfile(GetProfile());
545 if (prerenderer) {
546 const base::string16& search_terms =
547 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl);
548 if (!search_terms.empty() &&
549 prerenderer->CanCommitQuery(web_contents_.get(), search_terms)) {
550 EmbeddedSearchRequestParams request_params(gurl);
551 prerenderer->Commit(search_terms, request_params);
553 if (prerenderer->UsePrerenderedPage(gurl, &params))
554 return FULL_PRERENDERED_PAGE_LOAD;
556 prerenderer->Cancel();
558 if (prerender_manager->MaybeUsePrerenderedPage(gurl, &params)) {
559 return prefetched_page_loaded ?
560 FULL_PRERENDERED_PAGE_LOAD : PARTIAL_PRERENDERED_PAGE_LOAD;
564 GURL fixed_url(
565 url_fixer::FixupURL(gurl.possibly_invalid_spec(), std::string()));
566 if (!fixed_url.is_valid())
567 return PAGE_LOAD_FAILED;
569 if (!HandleNonNavigationAboutURL(fixed_url)) {
570 // Record UMA "ShowHistory" here. That way it'll pick up both user
571 // typing chrome://history as well as selecting from the drop down menu.
572 if (fixed_url.spec() == chrome::kChromeUIHistoryURL) {
573 content::RecordAction(base::UserMetricsAction("ShowHistory"));
576 content::NavigationController::LoadURLParams load_params(fixed_url);
577 if (j_extra_headers) {
578 load_params.extra_headers = base::android::ConvertJavaStringToUTF8(
579 env,
580 j_extra_headers);
582 if (j_post_data) {
583 load_params.load_type =
584 content::NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
585 std::vector<uint8> post_data;
586 base::android::JavaByteArrayToByteVector(env, j_post_data, &post_data);
587 load_params.browser_initiated_post_data =
588 base::RefCountedBytes::TakeVector(&post_data);
590 load_params.transition_type =
591 ui::PageTransitionFromInt(page_transition);
592 if (j_referrer_url) {
593 load_params.referrer = content::Referrer(
594 GURL(base::android::ConvertJavaStringToUTF8(env, j_referrer_url)),
595 static_cast<blink::WebReferrerPolicy>(referrer_policy));
597 const base::string16 search_terms =
598 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl);
599 SearchTabHelper* search_tab_helper =
600 SearchTabHelper::FromWebContents(web_contents_.get());
601 if (!search_terms.empty() && search_tab_helper &&
602 search_tab_helper->SupportsInstant()) {
603 EmbeddedSearchRequestParams request_params(gurl);
604 search_tab_helper->Submit(search_terms, request_params);
605 return DEFAULT_PAGE_LOAD;
607 load_params.is_renderer_initiated = is_renderer_initiated;
608 load_params.intent_received_timestamp = intent_received_timestamp;
609 web_contents()->GetController().LoadURLWithParams(load_params);
611 return DEFAULT_PAGE_LOAD;
614 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env,
615 jobject obj,
616 jstring jurl,
617 jstring jtitle) {
618 DCHECK(web_contents());
620 base::string16 title;
621 if (jtitle)
622 title = base::android::ConvertJavaStringToUTF16(env, jtitle);
624 std::string url;
625 if (jurl)
626 url = base::android::ConvertJavaStringToUTF8(env, jurl);
628 content::NavigationEntry* entry =
629 web_contents()->GetController().GetVisibleEntry();
630 if (entry && url == entry->GetVirtualURL().spec())
631 entry->SetTitle(title);
634 bool TabAndroid::Print(JNIEnv* env, jobject obj) {
635 if (!web_contents())
636 return false;
638 printing::PrintViewManagerBasic::CreateForWebContents(web_contents());
639 printing::PrintViewManagerBasic* print_view_manager =
640 printing::PrintViewManagerBasic::FromWebContents(web_contents());
641 if (print_view_manager == NULL)
642 return false;
644 print_view_manager->PrintNow();
645 return true;
648 void TabAndroid::SetPendingPrint() {
649 JNIEnv* env = base::android::AttachCurrentThread();
650 Java_Tab_setPendingPrint(env, weak_java_tab_.get(env).obj());
653 ScopedJavaLocalRef<jobject> TabAndroid::GetFavicon(JNIEnv* env,
654 jobject obj) {
656 ScopedJavaLocalRef<jobject> bitmap;
657 FaviconTabHelper* favicon_tab_helper =
658 FaviconTabHelper::FromWebContents(web_contents_.get());
660 if (!favicon_tab_helper)
661 return bitmap;
663 // Always return the default favicon in Android.
664 SkBitmap favicon = favicon_tab_helper->GetFavicon().AsBitmap();
665 if (!favicon.empty()) {
666 gfx::DeviceDisplayInfo device_info;
667 const float device_scale_factor = device_info.GetDIPScale();
668 int target_size_dip = device_scale_factor * gfx::kFaviconSize;
669 if (favicon.width() != target_size_dip ||
670 favicon.height() != target_size_dip) {
671 favicon =
672 skia::ImageOperations::Resize(favicon,
673 skia::ImageOperations::RESIZE_BEST,
674 target_size_dip,
675 target_size_dip);
678 bitmap = gfx::ConvertToJavaBitmap(&favicon);
680 return bitmap;
683 prerender::PrerenderManager* TabAndroid::GetPrerenderManager() const {
684 Profile* profile = GetProfile();
685 if (!profile)
686 return NULL;
687 return prerender::PrerenderManagerFactory::GetForProfile(profile);
690 // static
691 void TabAndroid::CreateHistoricalTabFromContents(WebContents* web_contents) {
692 DCHECK(web_contents);
694 TabRestoreService* service =
695 TabRestoreServiceFactory::GetForProfile(
696 Profile::FromBrowserContext(web_contents->GetBrowserContext()));
697 if (!service)
698 return;
700 // Exclude internal pages from being marked as recent when they are closed.
701 const GURL& tab_url = web_contents->GetURL();
702 if (tab_url.SchemeIs(content::kChromeUIScheme) ||
703 tab_url.SchemeIs(chrome::kChromeNativeScheme) ||
704 tab_url.SchemeIs(url::kAboutScheme)) {
705 return;
708 // TODO(jcivelli): is the index important?
709 service->CreateHistoricalTab(web_contents, -1);
712 void TabAndroid::CreateHistoricalTab(JNIEnv* env, jobject obj) {
713 TabAndroid::CreateHistoricalTabFromContents(web_contents());
716 void TabAndroid::UpdateTopControlsState(JNIEnv* env,
717 jobject obj,
718 jint constraints,
719 jint current,
720 jboolean animate) {
721 content::TopControlsState constraints_state =
722 static_cast<content::TopControlsState>(constraints);
723 content::TopControlsState current_state =
724 static_cast<content::TopControlsState>(current);
725 WebContents* sender = web_contents();
726 sender->Send(new ChromeViewMsg_UpdateTopControlsState(
727 sender->GetRoutingID(), constraints_state, current_state, animate));
730 void TabAndroid::SearchByImageInNewTabAsync(JNIEnv* env, jobject obj) {
731 content::RenderFrameHost* render_frame_host =
732 web_contents()->GetMainFrame();
733 render_frame_host->Send(
734 new ChromeViewMsg_RequestThumbnailForContextNode(
735 render_frame_host->GetRoutingID(),
736 kImageSearchThumbnailMinSize,
737 gfx::Size(kImageSearchThumbnailMaxWidth,
738 kImageSearchThumbnailMaxHeight)));
741 jlong TabAndroid::GetBookmarkId(JNIEnv* env,
742 jobject obj,
743 jboolean only_editable) {
744 const GURL& url = dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(
745 web_contents()->GetURL());
746 Profile* profile = GetProfile();
748 // Get all the nodes for |url| and sort them by date added.
749 std::vector<const bookmarks::BookmarkNode*> nodes;
750 ChromeBookmarkClient* client =
751 ChromeBookmarkClientFactory::GetForProfile(profile);
752 bookmarks::BookmarkModel* model =
753 BookmarkModelFactory::GetForProfile(profile);
754 model->GetNodesByURL(url, &nodes);
755 std::sort(nodes.begin(), nodes.end(), &bookmarks::MoreRecentlyAdded);
757 // Return the first node matching the search criteria.
758 for (size_t i = 0; i < nodes.size(); ++i) {
759 if (only_editable && !client->CanBeEditedByUser(nodes[i]))
760 continue;
761 return nodes[i]->id();
764 return -1;
767 namespace {
769 class ChromeInterceptNavigationDelegate : public InterceptNavigationDelegate {
770 public:
771 ChromeInterceptNavigationDelegate(JNIEnv* env, jobject jdelegate)
772 : InterceptNavigationDelegate(env, jdelegate) {}
774 bool ShouldIgnoreNavigation(
775 const NavigationParams& navigation_params) override {
776 NavigationParams chrome_navigation_params(navigation_params);
777 chrome_navigation_params.url() =
778 GURL(net::EscapeExternalHandlerValue(navigation_params.url().spec()));
779 return InterceptNavigationDelegate::ShouldIgnoreNavigation(
780 chrome_navigation_params);
784 } // namespace
786 void TabAndroid::SetInterceptNavigationDelegate(JNIEnv* env, jobject obj,
787 jobject delegate) {
788 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
789 InterceptNavigationDelegate::Associate(
790 web_contents(),
791 make_scoped_ptr(new ChromeInterceptNavigationDelegate(env, delegate)));
794 void TabAndroid::AttachToTabContentManager(JNIEnv* env,
795 jobject obj,
796 jobject jtab_content_manager) {
797 chrome::android::TabContentManager* tab_content_manager =
798 chrome::android::TabContentManager::FromJavaObject(jtab_content_manager);
799 if (tab_content_manager == tab_content_manager_)
800 return;
802 if (tab_content_manager_)
803 tab_content_manager_->DetachLiveLayer(GetAndroidId(), GetContentLayer());
804 tab_content_manager_ = tab_content_manager;
805 if (tab_content_manager_)
806 tab_content_manager_->AttachLiveLayer(GetAndroidId(), GetContentLayer());
809 void TabAndroid::AttachOverlayContentViewCore(JNIEnv* env,
810 jobject obj,
811 jobject jcontent_view_core,
812 jboolean visible) {
813 content::ContentViewCore* content_view_core =
814 content::ContentViewCore::GetNativeContentViewCore(env,
815 jcontent_view_core);
816 DCHECK(content_view_core);
818 content_view_core->GetLayer()->SetHideLayerAndSubtree(!visible);
819 content_layer_->AddChild(content_view_core->GetLayer());
822 void TabAndroid::DetachOverlayContentViewCore(JNIEnv* env,
823 jobject obj,
824 jobject jcontent_view_core) {
825 content::ContentViewCore* content_view_core =
826 content::ContentViewCore::GetNativeContentViewCore(env,
827 jcontent_view_core);
828 DCHECK(content_view_core);
830 content_view_core->GetLayer()->RemoveFromParent();
833 static void Init(JNIEnv* env, jobject obj) {
834 TRACE_EVENT0("native", "TabAndroid::Init");
835 // This will automatically bind to the Java object and pass ownership there.
836 new TabAndroid(env, obj);
839 // static
840 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
841 return RegisterNativesImpl(env);
844 static void RecordStartupToCommitUma(JNIEnv* env, jclass jcaller) {
845 // Currently it takes about 2000ms to commit a navigation if the measurement
846 // begins very early in the browser start. How many buckets (b) are needed to
847 // explore the _typical_ values with granularity 100ms and a maximum duration
848 // of 1 minute?
849 // s^{n+1} / s^{n} = 2100 / 2000
850 // s = 1.05
851 // s^b = 60000
852 // b = ln(60000) / ln(1.05) ~= 225
853 UMA_HISTOGRAM_CUSTOM_TIMES("Startup.FirstCommitNavigationTime",
854 base::Time::Now() - chrome::android::GetMainEntryPointTime(),
855 base::TimeDelta::FromMilliseconds(1),
856 base::TimeDelta::FromMinutes(1),
857 225);