// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/frame_host/navigation_controller_android.h" #include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "content/browser/frame_host/navigation_entry_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/ssl_host_state_delegate.h" #include "jni/NavigationControllerImpl_jni.h" #include "ui/gfx/android/java_bitmap.h" using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF16; using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF16ToJavaString; using base::android::ConvertUTF8ToJavaString; namespace { // static static base::android::ScopedJavaLocalRef CreateJavaNavigationEntry( JNIEnv* env, content::NavigationEntry* entry, int index) { DCHECK(entry); // Get the details of the current entry ScopedJavaLocalRef j_url( ConvertUTF8ToJavaString(env, entry->GetURL().spec())); ScopedJavaLocalRef j_virtual_url( ConvertUTF8ToJavaString(env, entry->GetVirtualURL().spec())); ScopedJavaLocalRef j_original_url( ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec())); ScopedJavaLocalRef j_title( ConvertUTF16ToJavaString(env, entry->GetTitle())); ScopedJavaLocalRef j_bitmap; const content::FaviconStatus& status = entry->GetFavicon(); if (status.valid && status.image.ToSkBitmap()->getSize() > 0) j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap()); return content::Java_NavigationControllerImpl_createNavigationEntry( env, index, j_url.obj(), j_virtual_url.obj(), j_original_url.obj(), j_title.obj(), j_bitmap.obj(), entry->GetTransitionType()); } static void AddNavigationEntryToHistory(JNIEnv* env, jobject history, content::NavigationEntry* entry, int index) { content::Java_NavigationControllerImpl_addToNavigationHistory( env, history, CreateJavaNavigationEntry(env, entry, index).obj()); } } // namespace namespace content { // static bool NavigationControllerAndroid::Register(JNIEnv* env) { return RegisterNativesImpl(env); } NavigationControllerAndroid::NavigationControllerAndroid( NavigationController* navigation_controller) : navigation_controller_(navigation_controller) { JNIEnv* env = AttachCurrentThread(); obj_.Reset(env, Java_NavigationControllerImpl_create( env, reinterpret_cast(this)).obj()); } NavigationControllerAndroid::~NavigationControllerAndroid() { Java_NavigationControllerImpl_destroy(AttachCurrentThread(), obj_.obj()); } base::android::ScopedJavaLocalRef NavigationControllerAndroid::GetJavaObject() { return base::android::ScopedJavaLocalRef(obj_); } jboolean NavigationControllerAndroid::CanGoBack(JNIEnv* env, jobject obj) { return navigation_controller_->CanGoBack(); } jboolean NavigationControllerAndroid::CanGoForward(JNIEnv* env, jobject obj) { return navigation_controller_->CanGoForward(); } jboolean NavigationControllerAndroid::CanGoToOffset(JNIEnv* env, jobject obj, jint offset) { return navigation_controller_->CanGoToOffset(offset); } void NavigationControllerAndroid::GoBack(JNIEnv* env, jobject obj) { navigation_controller_->GoBack(); } void NavigationControllerAndroid::GoForward(JNIEnv* env, jobject obj) { navigation_controller_->GoForward(); } void NavigationControllerAndroid::GoToOffset(JNIEnv* env, jobject obj, jint offset) { navigation_controller_->GoToOffset(offset); } jboolean NavigationControllerAndroid::IsInitialNavigation(JNIEnv* env, jobject obj) { return navigation_controller_->IsInitialNavigation(); } void NavigationControllerAndroid::LoadIfNecessary(JNIEnv* env, jobject obj) { navigation_controller_->LoadIfNecessary(); } void NavigationControllerAndroid::ContinuePendingReload(JNIEnv* env, jobject obj) { navigation_controller_->ContinuePendingReload(); } void NavigationControllerAndroid::Reload(JNIEnv* env, jobject obj, jboolean check_for_repost) { navigation_controller_->Reload(check_for_repost); } void NavigationControllerAndroid::ReloadIgnoringCache( JNIEnv* env, jobject obj, jboolean check_for_repost) { navigation_controller_->ReloadIgnoringCache(check_for_repost); } void NavigationControllerAndroid::RequestRestoreLoad(JNIEnv* env, jobject obj) { navigation_controller_->SetNeedsReload(); } void NavigationControllerAndroid::CancelPendingReload(JNIEnv* env, jobject obj) { navigation_controller_->CancelPendingReload(); } void NavigationControllerAndroid::GoToNavigationIndex(JNIEnv* env, jobject obj, jint index) { navigation_controller_->GoToIndex(index); } void NavigationControllerAndroid::LoadUrl(JNIEnv* env, jobject obj, jstring url, jint load_url_type, jint transition_type, jstring j_referrer_url, jint referrer_policy, jint ua_override_option, jstring extra_headers, jbyteArray post_data, jstring base_url_for_data_url, jstring virtual_url_for_data_url, jboolean can_load_local_resources, jboolean is_renderer_initiated) { DCHECK(url); NavigationController::LoadURLParams params( GURL(ConvertJavaStringToUTF8(env, url))); params.load_type = static_cast(load_url_type); params.transition_type = ui::PageTransitionFromInt(transition_type); params.override_user_agent = static_cast( ua_override_option); params.can_load_local_resources = can_load_local_resources; params.is_renderer_initiated = is_renderer_initiated; if (extra_headers) params.extra_headers = ConvertJavaStringToUTF8(env, extra_headers); if (post_data) { std::vector http_body_vector; base::android::JavaByteArrayToByteVector(env, post_data, &http_body_vector); params.browser_initiated_post_data = base::RefCountedBytes::TakeVector(&http_body_vector); } if (base_url_for_data_url) { params.base_url_for_data_url = GURL(ConvertJavaStringToUTF8(env, base_url_for_data_url)); } if (virtual_url_for_data_url) { params.virtual_url_for_data_url = GURL(ConvertJavaStringToUTF8(env, virtual_url_for_data_url)); } if (j_referrer_url) { params.referrer = content::Referrer( GURL(ConvertJavaStringToUTF8(env, j_referrer_url)), static_cast(referrer_policy)); } navigation_controller_->LoadURLWithParams(params); } void NavigationControllerAndroid::ClearHistory(JNIEnv* env, jobject obj) { // TODO(creis): Do callers of this need to know if it fails? if (navigation_controller_->CanPruneAllButLastCommitted()) navigation_controller_->PruneAllButLastCommitted(); } jint NavigationControllerAndroid::GetNavigationHistory(JNIEnv* env, jobject obj, jobject history) { // Iterate through navigation entries to populate the list int count = navigation_controller_->GetEntryCount(); for (int i = 0; i < count; ++i) { AddNavigationEntryToHistory( env, history, navigation_controller_->GetEntryAtIndex(i), i); } return navigation_controller_->GetCurrentEntryIndex(); } void NavigationControllerAndroid::GetDirectedNavigationHistory( JNIEnv* env, jobject obj, jobject history, jboolean is_forward, jint max_entries) { // Iterate through navigation entries to populate the list int count = navigation_controller_->GetEntryCount(); int num_added = 0; int increment_value = is_forward ? 1 : -1; for (int i = navigation_controller_->GetCurrentEntryIndex() + increment_value; i >= 0 && i < count; i += increment_value) { if (num_added >= max_entries) break; AddNavigationEntryToHistory( env, history, navigation_controller_->GetEntryAtIndex(i), i); num_added++; } } ScopedJavaLocalRef NavigationControllerAndroid::GetOriginalUrlForVisibleNavigationEntry( JNIEnv* env, jobject obj) { NavigationEntry* entry = navigation_controller_->GetVisibleEntry(); if (entry == NULL) return ScopedJavaLocalRef(env, NULL); return ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()); } void NavigationControllerAndroid::ClearSslPreferences(JNIEnv* env, jobject obj) { content::SSLHostStateDelegate* delegate = navigation_controller_->GetBrowserContext()->GetSSLHostStateDelegate(); if (delegate) delegate->Clear(); } bool NavigationControllerAndroid::GetUseDesktopUserAgent(JNIEnv* env, jobject obj) { NavigationEntry* entry = navigation_controller_->GetVisibleEntry(); return entry && entry->GetIsOverridingUserAgent(); } void NavigationControllerAndroid::SetUseDesktopUserAgent( JNIEnv* env, jobject obj, jboolean enabled, jboolean reload_on_state_change) { if (GetUseDesktopUserAgent(env, obj) == enabled) return; // Make sure the navigation entry actually exists. NavigationEntry* entry = navigation_controller_->GetVisibleEntry(); if (!entry) return; // Set the flag in the NavigationEntry. entry->SetIsOverridingUserAgent(enabled); // Send the override to the renderer. if (reload_on_state_change) { // Reloading the page will send the override down as part of the // navigation IPC message. navigation_controller_->ReloadOriginalRequestURL(false); } } base::android::ScopedJavaLocalRef NavigationControllerAndroid::GetEntryAtIndex(JNIEnv* env, jobject obj, int index) { if (index < 0 || index >= navigation_controller_->GetEntryCount()) return base::android::ScopedJavaLocalRef(); content::NavigationEntry* entry = navigation_controller_->GetEntryAtIndex(index); return CreateJavaNavigationEntry(env, entry, index); } base::android::ScopedJavaLocalRef NavigationControllerAndroid::GetPendingEntry(JNIEnv* env, jobject obj) { content::NavigationEntry* entry = navigation_controller_->GetPendingEntry(); if (!entry) return base::android::ScopedJavaLocalRef(); return CreateJavaNavigationEntry( env, entry, navigation_controller_->GetPendingEntryIndex()); } jint NavigationControllerAndroid::GetLastCommittedEntryIndex(JNIEnv* env, jobject obj) { return navigation_controller_->GetLastCommittedEntryIndex(); } jboolean NavigationControllerAndroid::RemoveEntryAtIndex(JNIEnv* env, jobject obj, jint index) { return navigation_controller_->RemoveEntryAtIndex(index); } } // namespace content