Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / android / tab_android.cc
blobf831f2172bb7a1879925733df3945f509811826f
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/google/google_url_tracker.h"
16 #include "chrome/browser/google/google_util.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/ui/android/content_settings/popup_blocked_infobar_delegate.h"
28 #include "chrome/browser/ui/android/context_menu_helper.h"
29 #include "chrome/browser/ui/android/infobars/infobar_container_android.h"
30 #include "chrome/browser/ui/android/tab_model/tab_model.h"
31 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
32 #include "chrome/browser/ui/android/window_android_helper.h"
33 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
34 #include "chrome/browser/ui/search/search_tab_helper.h"
35 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
36 #include "chrome/browser/ui/tab_helpers.h"
37 #include "chrome/browser/ui/toolbar/toolbar_model_impl.h"
38 #include "chrome/common/net/url_fixer_upper.h"
39 #include "chrome/common/url_constants.h"
40 #include "components/infobars/core/infobar_container.h"
41 #include "content/public/browser/android/content_view_core.h"
42 #include "content/public/browser/navigation_entry.h"
43 #include "content/public/browser/notification_service.h"
44 #include "content/public/browser/user_metrics.h"
45 #include "content/public/browser/web_contents.h"
46 #include "jni/Tab_jni.h"
47 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
49 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
50 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
51 if (!core_tab_helper)
52 return NULL;
54 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
55 if (!core_delegate)
56 return NULL;
58 return static_cast<TabAndroid*>(core_delegate);
61 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
62 return reinterpret_cast<TabAndroid*>(Java_Tab_getNativePtr(env, obj));
65 void TabAndroid::AttachTabHelpers(content::WebContents* web_contents) {
66 DCHECK(web_contents);
68 TabHelpers::AttachTabHelpers(web_contents);
71 TabAndroid::TabAndroid(JNIEnv* env, jobject obj)
72 : weak_java_tab_(env, obj),
73 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
74 Java_Tab_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this));
77 TabAndroid::~TabAndroid() {
78 JNIEnv* env = base::android::AttachCurrentThread();
79 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
80 if (obj.is_null())
81 return;
83 Java_Tab_clearNativePtr(env, obj.obj());
86 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() {
87 JNIEnv* env = base::android::AttachCurrentThread();
88 return weak_java_tab_.get(env);
91 int TabAndroid::GetAndroidId() const {
92 JNIEnv* env = base::android::AttachCurrentThread();
93 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
94 if (obj.is_null())
95 return -1;
96 return Java_Tab_getId(env, obj.obj());
99 int TabAndroid::GetSyncId() const {
100 JNIEnv* env = base::android::AttachCurrentThread();
101 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
102 if (obj.is_null())
103 return 0;
104 return Java_Tab_getSyncId(env, obj.obj());
107 base::string16 TabAndroid::GetTitle() const {
108 JNIEnv* env = base::android::AttachCurrentThread();
109 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
110 if (obj.is_null())
111 return base::string16();
112 return base::android::ConvertJavaStringToUTF16(
113 Java_Tab_getTitle(env, obj.obj()));
116 GURL TabAndroid::GetURL() const {
117 JNIEnv* env = base::android::AttachCurrentThread();
118 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
119 if (obj.is_null())
120 return GURL::EmptyGURL();
121 return GURL(base::android::ConvertJavaStringToUTF8(
122 Java_Tab_getUrl(env, obj.obj())));
125 bool TabAndroid::LoadIfNeeded() {
126 JNIEnv* env = base::android::AttachCurrentThread();
127 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
128 if (obj.is_null())
129 return false;
130 return Java_Tab_loadIfNeeded(env, obj.obj());
133 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
134 if (!web_contents())
135 return NULL;
137 return content::ContentViewCore::FromWebContents(web_contents());
140 Profile* TabAndroid::GetProfile() const {
141 if (!web_contents())
142 return NULL;
144 return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
147 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
148 return synced_tab_delegate_.get();
151 void TabAndroid::SetWindowSessionID(SessionID::id_type window_id) {
152 session_window_id_.set_id(window_id);
154 if (!web_contents())
155 return;
157 SessionTabHelper* session_tab_helper =
158 SessionTabHelper::FromWebContents(web_contents());
159 session_tab_helper->SetWindowID(session_window_id_);
162 void TabAndroid::SetSyncId(int sync_id) {
163 JNIEnv* env = base::android::AttachCurrentThread();
164 ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
165 if (obj.is_null())
166 return;
167 Java_Tab_setSyncId(env, obj.obj(), sync_id);
170 void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) {
171 NOTIMPLEMENTED();
174 void TabAndroid::OnReceivedHttpAuthRequest(jobject auth_handler,
175 const base::string16& host,
176 const base::string16& realm) {
177 NOTIMPLEMENTED();
180 bool TabAndroid::ShouldWelcomePageLinkToTermsOfService() {
181 NOTIMPLEMENTED();
182 return false;
185 bool TabAndroid::HasPrerenderedUrl(GURL gurl) {
186 prerender::PrerenderManager* prerender_manager = GetPrerenderManager();
187 if (!prerender_manager)
188 return false;
190 std::vector<content::WebContents*> contents =
191 prerender_manager->GetAllPrerenderingContents();
192 prerender::PrerenderContents* prerender_contents;
193 for (size_t i = 0; i < contents.size(); ++i) {
194 prerender_contents = prerender_manager->
195 GetPrerenderContents(contents.at(i));
196 if (prerender_contents->prerender_url() == gurl &&
197 prerender_contents->has_finished_loading()) {
198 return true;
201 return false;
204 void TabAndroid::SwapTabContents(content::WebContents* old_contents,
205 content::WebContents* new_contents,
206 bool did_start_load,
207 bool did_finish_load) {
208 JNIEnv* env = base::android::AttachCurrentThread();
210 // We need to notify the native InfobarContainer so infobars can be swapped.
211 InfoBarContainerAndroid* infobar_container =
212 reinterpret_cast<InfoBarContainerAndroid*>(
213 Java_Tab_getNativeInfoBarContainer(
214 env,
215 weak_java_tab_.get(env).obj()));
216 InfoBarService* new_infobar_service =
217 new_contents ? InfoBarService::FromWebContents(new_contents) : NULL;
218 infobar_container->ChangeInfoBarManager(new_infobar_service);
220 Java_Tab_swapWebContents(
221 env,
222 weak_java_tab_.get(env).obj(),
223 reinterpret_cast<intptr_t>(new_contents),
224 did_start_load,
225 did_finish_load);
228 void TabAndroid::Observe(int type,
229 const content::NotificationSource& source,
230 const content::NotificationDetails& details) {
231 JNIEnv* env = base::android::AttachCurrentThread();
232 switch (type) {
233 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: {
234 TabSpecificContentSettings* settings =
235 TabSpecificContentSettings::FromWebContents(web_contents());
236 if (!settings->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS)) {
237 // TODO(dfalcantara): Create an InfoBarDelegate to keep the
238 // PopupBlockedInfoBar logic native-side instead of straddling the JNI
239 // boundary.
240 int num_popups = 0;
241 PopupBlockerTabHelper* popup_blocker_helper =
242 PopupBlockerTabHelper::FromWebContents(web_contents());
243 if (popup_blocker_helper)
244 num_popups = popup_blocker_helper->GetBlockedPopupsCount();
246 if (num_popups > 0)
247 PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups);
249 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS);
251 break;
253 case chrome::NOTIFICATION_FAVICON_UPDATED:
254 Java_Tab_onFaviconUpdated(env, weak_java_tab_.get(env).obj());
255 break;
256 case content::NOTIFICATION_NAV_ENTRY_CHANGED:
257 Java_Tab_onNavEntryChanged(env, weak_java_tab_.get(env).obj());
258 break;
259 default:
260 NOTREACHED() << "Unexpected notification " << type;
261 break;
265 void TabAndroid::Destroy(JNIEnv* env, jobject obj) {
266 delete this;
269 void TabAndroid::InitWebContents(JNIEnv* env,
270 jobject obj,
271 jboolean incognito,
272 jobject jcontent_view_core,
273 jobject jweb_contents_delegate,
274 jobject jcontext_menu_populator) {
275 content::ContentViewCore* content_view_core =
276 content::ContentViewCore::GetNativeContentViewCore(env,
277 jcontent_view_core);
278 DCHECK(content_view_core);
279 DCHECK(content_view_core->GetWebContents());
281 web_contents_.reset(content_view_core->GetWebContents());
282 AttachTabHelpers(web_contents_.get());
284 SetWindowSessionID(session_window_id_.id());
286 session_tab_id_.set_id(
287 SessionTabHelper::FromWebContents(web_contents())->session_id().id());
288 ContextMenuHelper::FromWebContents(web_contents())->SetPopulator(
289 jcontext_menu_populator);
290 WindowAndroidHelper::FromWebContents(web_contents())->
291 SetWindowAndroid(content_view_core->GetWindowAndroid());
292 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this);
293 web_contents_delegate_.reset(
294 new chrome::android::ChromeWebContentsDelegateAndroid(
295 env, jweb_contents_delegate));
296 web_contents_delegate_->LoadProgressChanged(web_contents(), 0);
297 web_contents()->SetDelegate(web_contents_delegate_.get());
299 notification_registrar_.Add(
300 this,
301 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
302 content::Source<content::WebContents>(web_contents()));
303 notification_registrar_.Add(
304 this,
305 chrome::NOTIFICATION_FAVICON_UPDATED,
306 content::Source<content::WebContents>(web_contents()));
307 notification_registrar_.Add(
308 this,
309 content::NOTIFICATION_NAV_ENTRY_CHANGED,
310 content::Source<content::NavigationController>(
311 &web_contents()->GetController()));
313 synced_tab_delegate_->SetWebContents(web_contents());
315 // Verify that the WebContents this tab represents matches the expected
316 // off the record state.
317 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito);
320 void TabAndroid::DestroyWebContents(JNIEnv* env,
321 jobject obj,
322 jboolean delete_native) {
323 DCHECK(web_contents());
325 notification_registrar_.Remove(
326 this,
327 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
328 content::Source<content::WebContents>(web_contents()));
329 notification_registrar_.Remove(
330 this,
331 chrome::NOTIFICATION_FAVICON_UPDATED,
332 content::Source<content::WebContents>(web_contents()));
333 notification_registrar_.Remove(
334 this,
335 content::NOTIFICATION_NAV_ENTRY_CHANGED,
336 content::Source<content::NavigationController>(
337 &web_contents()->GetController()));
339 web_contents()->SetDelegate(NULL);
341 if (delete_native) {
342 web_contents_.reset();
343 synced_tab_delegate_->ResetWebContents();
344 } else {
345 // Release the WebContents so it does not get deleted by the scoped_ptr.
346 ignore_result(web_contents_.release());
350 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetWebContents(
351 JNIEnv* env,
352 jobject obj) {
353 if (!web_contents_.get())
354 return base::android::ScopedJavaLocalRef<jobject>();
355 return web_contents_->GetJavaWebContents();
358 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid(
359 JNIEnv* env,
360 jobject obj) {
361 Profile* profile = GetProfile();
362 if (!profile)
363 return base::android::ScopedJavaLocalRef<jobject>();
364 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
365 if (!profile_android)
366 return base::android::ScopedJavaLocalRef<jobject>();
368 return profile_android->GetJavaObject();
371 TabAndroid::TabLoadStatus TabAndroid::LoadUrl(JNIEnv* env,
372 jobject obj,
373 jstring url,
374 jstring j_extra_headers,
375 jbyteArray j_post_data,
376 jint page_transition,
377 jstring j_referrer_url,
378 jint referrer_policy) {
379 content::ContentViewCore* content_view = GetContentViewCore();
380 if (!content_view)
381 return PAGE_LOAD_FAILED;
383 GURL gurl(base::android::ConvertJavaStringToUTF8(env, url));
384 if (gurl.is_empty())
385 return PAGE_LOAD_FAILED;
387 // If the page was prerendered, use it.
388 // Note in incognito mode, we don't have a PrerenderManager.
390 prerender::PrerenderManager* prerender_manager =
391 prerender::PrerenderManagerFactory::GetForProfile(GetProfile());
392 if (prerender_manager) {
393 bool prefetched_page_loaded = HasPrerenderedUrl(gurl);
394 // Getting the load status before MaybeUsePrerenderedPage() b/c it resets.
395 chrome::NavigateParams params(NULL, web_contents());
396 if (prerender_manager->MaybeUsePrerenderedPage(gurl, &params)) {
397 return prefetched_page_loaded ?
398 FULL_PRERENDERED_PAGE_LOAD : PARTIAL_PRERENDERED_PAGE_LOAD;
402 GURL fixed_url(URLFixerUpper::FixupURL(gurl.possibly_invalid_spec(),
403 std::string()));
404 if (!fixed_url.is_valid())
405 return PAGE_LOAD_FAILED;
407 if (!HandleNonNavigationAboutURL(fixed_url)) {
408 // Notify the GoogleURLTracker of searches, it might want to change the
409 // actual Google site used (for instance when in the UK, google.co.uk, when
410 // in the US google.com).
411 // Note that this needs to happen before we initiate the navigation as the
412 // GoogleURLTracker uses the navigation pending notification to trigger the
413 // infobar.
414 if (google_util::IsGoogleSearchUrl(fixed_url) &&
415 (page_transition & content::PAGE_TRANSITION_GENERATED)) {
416 GoogleURLTracker::GoogleURLSearchCommitted(GetProfile());
419 // Record UMA "ShowHistory" here. That way it'll pick up both user
420 // typing chrome://history as well as selecting from the drop down menu.
421 if (fixed_url.spec() == chrome::kChromeUIHistoryURL) {
422 content::RecordAction(base::UserMetricsAction("ShowHistory"));
425 content::NavigationController::LoadURLParams load_params(fixed_url);
426 if (j_extra_headers) {
427 load_params.extra_headers = base::android::ConvertJavaStringToUTF8(
428 env,
429 j_extra_headers);
431 if (j_post_data) {
432 load_params.load_type =
433 content::NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
434 std::vector<uint8> post_data;
435 base::android::JavaByteArrayToByteVector(env, j_post_data, &post_data);
436 load_params.browser_initiated_post_data =
437 base::RefCountedBytes::TakeVector(&post_data);
439 load_params.transition_type =
440 content::PageTransitionFromInt(page_transition);
441 if (j_referrer_url) {
442 load_params.referrer = content::Referrer(
443 GURL(base::android::ConvertJavaStringToUTF8(env, j_referrer_url)),
444 static_cast<blink::WebReferrerPolicy>(referrer_policy));
446 const base::string16 search_terms =
447 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl);
448 SearchTabHelper* search_tab_helper =
449 SearchTabHelper::FromWebContents(web_contents_.get());
450 if (!search_terms.empty() && search_tab_helper &&
451 search_tab_helper->SupportsInstant()) {
452 search_tab_helper->Submit(search_terms);
453 return DEFAULT_PAGE_LOAD;
455 content_view->LoadUrl(load_params);
457 return DEFAULT_PAGE_LOAD;
460 ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env,
461 jobject obj) {
462 return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents());
465 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env,
466 jobject obj,
467 jstring jurl,
468 jstring jtitle) {
469 DCHECK(web_contents());
471 base::string16 title;
472 if (jtitle)
473 title = base::android::ConvertJavaStringToUTF16(env, jtitle);
475 std::string url;
476 if (jurl)
477 url = base::android::ConvertJavaStringToUTF8(env, jurl);
479 content::NavigationEntry* entry =
480 web_contents()->GetController().GetVisibleEntry();
481 if (entry && url == entry->GetVirtualURL().spec())
482 entry->SetTitle(title);
485 bool TabAndroid::Print(JNIEnv* env, jobject obj) {
486 if (!web_contents())
487 return false;
489 printing::PrintViewManagerBasic::CreateForWebContents(web_contents());
490 printing::PrintViewManagerBasic* print_view_manager =
491 printing::PrintViewManagerBasic::FromWebContents(web_contents());
492 if (print_view_manager == NULL)
493 return false;
495 print_view_manager->PrintNow();
496 return true;
499 prerender::PrerenderManager* TabAndroid::GetPrerenderManager() const {
500 Profile* profile = GetProfile();
501 if (!profile)
502 return NULL;
503 return prerender::PrerenderManagerFactory::GetForProfile(profile);
506 static void Init(JNIEnv* env, jobject obj) {
507 TRACE_EVENT0("native", "TabAndroid::Init");
508 // This will automatically bind to the Java object and pass ownership there.
509 new TabAndroid(env, obj);
512 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
513 return RegisterNativesImpl(env);