| Index: chrome/browser/component/web_contents_delegate_android/web_contents_delegate_android.cc
|
| diff --git a/chrome/browser/component/web_contents_delegate_android/web_contents_delegate_android.cc b/chrome/browser/component/web_contents_delegate_android/web_contents_delegate_android.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6659e2b14624038ce8e1585d5154ad39cb39882a
|
| --- /dev/null
|
| +++ b/chrome/browser/component/web_contents_delegate_android/web_contents_delegate_android.cc
|
| @@ -0,0 +1,357 @@
|
| +// Copyright (c) 2012 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 "chrome/browser/component/web_contents_delegate_android/web_contents_delegate_android.h"
|
| +
|
| +#include <android/keycodes.h>
|
| +
|
| +#include "base/android/jni_android.h"
|
| +#include "base/android/jni_string.h"
|
| +#include "content/public/browser/render_widget_host_view.h"
|
| +#include "content/public/browser/download_item.h"
|
| +#include "content/public/browser/invalidate_type.h"
|
| +#include "content/public/browser/page_navigator.h"
|
| +#include "content/public/browser/navigation_controller.h"
|
| +#include "content/public/browser/navigation_entry.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "content/public/common/page_transition_types.h"
|
| +#include "content/public/common/referrer.h"
|
| +#include "jni/WebContentsDelegateAndroid_jni.h"
|
| +#include "net/http/http_request_headers.h"
|
| +#include "ui/gfx/rect.h"
|
| +#include "webkit/glue/window_open_disposition.h"
|
| +
|
| +using base::android::AttachCurrentThread;
|
| +using base::android::CheckException;
|
| +using base::android::ConvertUTF8ToJavaString;
|
| +using base::android::ConvertUTF16ToJavaString;
|
| +using base::android::GetClass;
|
| +using base::android::GetMethodID;
|
| +using base::android::HasClass;
|
| +using base::android::ScopedJavaLocalRef;
|
| +using content::DownloadItem;
|
| +using content::JavaScriptDialogCreator;
|
| +using content::RenderViewHost;
|
| +using content::WebContents;
|
| +
|
| +namespace web_contents_delegate_android {
|
| +
|
| +WebContentsDelegateAndroid::WebContentsDelegateAndroid(JNIEnv* env, jobject obj)
|
| + : weak_java_delegate_(env, obj),
|
| + javascript_dialog_creator_(NULL) {
|
| +}
|
| +
|
| +WebContentsDelegateAndroid::~WebContentsDelegateAndroid() {
|
| +}
|
| +
|
| +ScopedJavaLocalRef<jobject>
|
| +WebContentsDelegateAndroid::GetJavaDelegate(JNIEnv* env) const {
|
| + return weak_java_delegate_.get(env);
|
| +}
|
| +
|
| +// ----------------------------------------------------------------------------
|
| +// WebContentsDelegate methods
|
| +// ----------------------------------------------------------------------------
|
| +
|
| +// OpenURLFromTab() will be called when we're performing a browser-intiated
|
| +// navigation. The most common scenario for this is opening new tabs (see
|
| +// RenderViewImpl::decidePolicyForNavigation for more details).
|
| +WebContents* WebContentsDelegateAndroid::OpenURLFromTab(
|
| + WebContents* source,
|
| + const content::OpenURLParams& params) {
|
| + const GURL& url = params.url;
|
| + WindowOpenDisposition disposition = params.disposition;
|
| + content::PageTransition transition(
|
| + PageTransitionFromInt(params.transition));
|
| +
|
| + if (!source || (disposition != CURRENT_TAB &&
|
| + disposition != NEW_FOREGROUND_TAB &&
|
| + disposition != NEW_BACKGROUND_TAB &&
|
| + disposition != OFF_THE_RECORD)) {
|
| + NOTIMPLEMENTED();
|
| + return NULL;
|
| + }
|
| +
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return WebContentsDelegate::OpenURLFromTab(source, params);
|
| +
|
| + if (disposition == NEW_FOREGROUND_TAB ||
|
| + disposition == NEW_BACKGROUND_TAB ||
|
| + disposition == OFF_THE_RECORD) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jstring> java_url =
|
| + ConvertUTF8ToJavaString(env, url.spec());
|
| + Java_WebContentsDelegateAndroid_openNewTab(env,
|
| + obj.obj(),
|
| + java_url.obj(),
|
| + disposition == OFF_THE_RECORD);
|
| + return NULL;
|
| + }
|
| +
|
| + // TODO(mkosiba): This should be in platform_utils OpenExternal, b/6174564.
|
| + if (transition == content::PAGE_TRANSITION_LINK && ShouldOverrideLoading(url))
|
| + return NULL;
|
| +
|
| + source->GetController().LoadURL(url, params.referrer, transition,
|
| + std::string());
|
| + return source;
|
| +}
|
| +
|
| +// ShouldIgnoreNavigation will be called for every non-local top level
|
| +// navigation made by the renderer. If true is returned the renderer will
|
| +// not perform the navigation. This is done by using synchronous IPC so we
|
| +// should avoid blocking calls from this method.
|
| +bool WebContentsDelegateAndroid::ShouldIgnoreNavigation(
|
| + WebContents* source,
|
| + const GURL& url,
|
| + const content::Referrer& referrer,
|
| + WindowOpenDisposition disposition,
|
| + content::PageTransition transition_type) {
|
| +
|
| + // Don't override new tabs.
|
| + if (disposition == NEW_FOREGROUND_TAB ||
|
| + disposition == NEW_BACKGROUND_TAB ||
|
| + disposition == OFF_THE_RECORD)
|
| + return false;
|
| +
|
| + return ShouldOverrideLoading(url);
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::NavigationStateChanged(
|
| + const WebContents* source, unsigned changed_flags) {
|
| + if (changed_flags & (
|
| + content::INVALIDATE_TYPE_TAB | content::INVALIDATE_TYPE_TITLE)) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return;
|
| + Java_WebContentsDelegateAndroid_onTabHeaderStateChanged(
|
| + env, obj.obj());
|
| + }
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::AddNewContents(
|
| + WebContents* source,
|
| + WebContents* new_contents,
|
| + WindowOpenDisposition disposition,
|
| + const gfx::Rect& initial_pos,
|
| + bool user_gesture) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + bool handled = false;
|
| + if (!obj.is_null()) {
|
| + handled = Java_WebContentsDelegateAndroid_addNewContents(
|
| + env,
|
| + obj.obj(),
|
| + reinterpret_cast<jint>(source),
|
| + reinterpret_cast<jint>(new_contents),
|
| + static_cast<jint>(disposition),
|
| + NULL,
|
| + user_gesture);
|
| + }
|
| + if (!handled)
|
| + delete new_contents;
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::ActivateContents(WebContents* contents) {
|
| + // TODO(dtrainor) When doing the merge I came across this. Should we be
|
| + // activating this tab here?
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::DeactivateContents(WebContents* contents) {
|
| + // Do nothing.
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::LoadingStateChanged(WebContents* source) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return;
|
| + bool has_stopped = source == NULL || !source->IsLoading();
|
| +
|
| + if (has_stopped)
|
| + Java_WebContentsDelegateAndroid_onLoadStopped(env, obj.obj());
|
| + else
|
| + Java_WebContentsDelegateAndroid_onLoadStarted(env, obj.obj());
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::LoadProgressChanged(WebContents* source,
|
| + double progress) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return;
|
| + Java_WebContentsDelegateAndroid_onLoadProgressChanged(
|
| + env,
|
| + obj.obj(),
|
| + progress);
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::CloseContents(WebContents* source) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return;
|
| + Java_WebContentsDelegateAndroid_closeContents(env, obj.obj());
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::MoveContents(WebContents* source,
|
| + const gfx::Rect& pos) {
|
| + // Do nothing.
|
| +}
|
| +
|
| +bool WebContentsDelegateAndroid::AddMessageToConsole(
|
| + WebContents* source,
|
| + int32 level,
|
| + const string16& message,
|
| + int32 line_no,
|
| + const string16& source_id) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return WebContentsDelegate::AddMessageToConsole(source, level, message,
|
| + line_no, source_id);
|
| + ScopedJavaLocalRef<jstring> jmessage(ConvertUTF16ToJavaString(env, message));
|
| + ScopedJavaLocalRef<jstring> jsource_id(
|
| + ConvertUTF16ToJavaString(env, source_id));
|
| + int jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_TIP;
|
| + switch (level) {
|
| + case logging::LOG_VERBOSE:
|
| + jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_TIP;
|
| + break;
|
| + case logging::LOG_INFO:
|
| + jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_LOG;
|
| + break;
|
| + case logging::LOG_WARNING:
|
| + jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_WARNING;
|
| + break;
|
| + case logging::LOG_ERROR:
|
| + jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_ERROR;
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| + return Java_WebContentsDelegateAndroid_addMessageToConsole(
|
| + env,
|
| + GetJavaDelegate(env).obj(),
|
| + jlevel,
|
| + jmessage.obj(),
|
| + line_no,
|
| + jsource_id.obj());
|
| +}
|
| +
|
| +// TODO(merge): WARNING! method no longer available on the base class.
|
| +// See http://b/issue?id=5862108
|
| +void WebContentsDelegateAndroid::URLStarredChanged(WebContents* source,
|
| + bool starred) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return;
|
| + Java_WebContentsDelegateAndroid_onUrlStarredChanged(env, obj.obj(), starred);
|
| +}
|
| +
|
| +// This is either called from TabContents::DidNavigateMainFramePostCommit() with
|
| +// an empty GURL or responding to RenderViewHost::OnMsgUpateTargetURL(). In
|
| +// Chrome, the latter is not always called, especially not during history
|
| +// navigation. So we only handle the first case and pass the source TabContents'
|
| +// url to Java to update the UI.
|
| +void WebContentsDelegateAndroid::UpdateTargetURL(WebContents* source,
|
| + int32 page_id,
|
| + const GURL& url) {
|
| + if (!url.is_empty())
|
| + return;
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return;
|
| + ScopedJavaLocalRef<jstring> java_url =
|
| + ConvertUTF8ToJavaString(env, source->GetURL().spec());
|
| + Java_WebContentsDelegateAndroid_onUpdateUrl(env,
|
| + obj.obj(),
|
| + java_url.obj());
|
| +}
|
| +
|
| +bool WebContentsDelegateAndroid::CanDownload(
|
| + RenderViewHost* source,
|
| + int request_id,
|
| + const std::string& request_method) {
|
| + if (request_method == net::HttpRequestHeaders::kGetMethod) {
|
| + // TODO(leandrogracia): re-enable this when calling DownloadController
|
| + // doesn't introduce a DEPS layering violation.
|
| + // DownloadController::GetInstance()->CreateGETDownload(
|
| + // source, request_id);
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::OnStartDownload(WebContents* source,
|
| + DownloadItem* download) {
|
| + // TODO(leandrogracia): re-enable this when calling DownloadController
|
| + // doesn't introduce a DEPS layering violation.
|
| + // DownloadController::GetInstance()->OnPostDownloadStarted(
|
| + // source, download);
|
| +}
|
| +
|
| +bool WebContentsDelegateAndroid::ShouldOverrideLoading(const GURL& url) {
|
| + if (!url.is_valid())
|
| + return false;
|
| +
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return WebContentsDelegate::ShouldOverrideLoading(url);
|
| + ScopedJavaLocalRef<jstring> jstring_url =
|
| + ConvertUTF8ToJavaString(env, url.spec());
|
| + bool ret = Java_WebContentsDelegateAndroid_shouldOverrideUrlLoading(
|
| + env, obj.obj(), jstring_url.obj());
|
| + return ret;
|
| +}
|
| +
|
| +void WebContentsDelegateAndroid::HandleKeyboardEvent(
|
| + content::WebContents* source,
|
| + const content::NativeWebKeyboardEvent& event) {
|
| + jobject key_event = event.os_event;
|
| + if (key_event) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return;
|
| + Java_WebContentsDelegateAndroid_handleKeyboardEvent(
|
| + env, obj.obj(), key_event);
|
| + }
|
| +}
|
| +
|
| +bool WebContentsDelegateAndroid::TakeFocus(WebContents* source, bool reverse) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
| + if (obj.is_null())
|
| + return WebContentsDelegate::TakeFocus(source, reverse);
|
| + return Java_WebContentsDelegateAndroid_takeFocus(
|
| + env, obj.obj(), reverse);
|
| +}
|
| +
|
| +JavaScriptDialogCreator*
|
| + WebContentsDelegateAndroid::GetJavaScriptDialogCreator() {
|
| + return javascript_dialog_creator_;
|
| +}
|
| +
|
| +// ----------------------------------------------------------------------------
|
| +// Native JNI methods
|
| +// ----------------------------------------------------------------------------
|
| +
|
| +// Register native methods
|
| +
|
| +bool RegisterWebContentsDelegateAndroid(JNIEnv* env) {
|
| + if (!HasClass(env, kWebContentsDelegateAndroidClassPath)) {
|
| + DLOG(ERROR) << "Unable to find class WebContentsDelegateAndroid!";
|
| + return false;
|
| + }
|
| + return RegisterNativesImpl(env);
|
| +}
|
| +
|
| +} // namespace web_contents_delegate_android
|
|
|