diff options
author | benm@chromium.org <benm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-15 16:39:44 +0000 |
---|---|---|
committer | benm@chromium.org <benm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-15 16:39:44 +0000 |
commit | 5daf9a9c800237b611c5c78fa973b75e5fd7a1a9 (patch) | |
tree | 028dfbc59c5f9056c5ffd9913555f5fe73a2f11a /android_webview | |
parent | aa7e9157c11105268e3c73d788c544d0511a7ff2 (diff) | |
download | chromium_src-5daf9a9c800237b611c5c78fa973b75e5fd7a1a9.zip chromium_src-5daf9a9c800237b611c5c78fa973b75e5fd7a1a9.tar.gz chromium_src-5daf9a9c800237b611c5c78fa973b75e5fd7a1a9.tar.bz2 |
[Android WebView] AwContentsClient.shouldCreateWindow callback part 1.
Provide the plumbing from WebContentsDelegate out to AwContentsClient
to allow the embedder to respond to requests to create pop up windows.
For now we only support the embedder blocking the pop up window; code
to support showing the window to follow in a later patch.
Note that the AwResourceDispatcherHostDelegate is refactored to
support lazily checking the AwContentsIoThreadClient, as we may
receive resource requests for the popup window before the Java
side has been entirely hooked up.
Android bots happy.
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/11362183
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167933 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview')
10 files changed, 144 insertions, 50 deletions
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index 7caa743..e579e22 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc @@ -237,10 +237,17 @@ bool AwContentBrowserClient::CanCreateWindow( content::ResourceContext* context, int render_process_id, bool* no_javascript_access) { - // TODO(boliu): Implement this to power SupportMultipleWindow. - NOTIMPLEMENTED(); - *no_javascript_access = false; - return false; + // We unconditionally allow popup windows at this stage and will give + // the embedder the opporunity to handle displaying of the popup in + // WebContentsDelegate::AddContents (via the + // AwContentsClient.onCreateWindow callback). + // Note that if the embedder has blocked support for creating popup + // windows through AwSettings, then we won't get to this point as + // the popup creation will have been blocked at the WebKit level. + if (no_javascript_access) { + *no_javascript_access = false; + } + return true; } std::string AwContentBrowserClient::GetWorkerProcessTitle(const GURL& url, diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc index c04a00f..a8d8c93 100644 --- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc +++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc @@ -22,17 +22,82 @@ using content::InterceptNavigationDelegate; namespace { +using android_webview::AwContentsIoThreadClient; + base::LazyInstance<android_webview::AwResourceDispatcherHostDelegate> g_webview_resource_dispatcher_host_delegate = LAZY_INSTANCE_INITIALIZER; -// Will unconditionally cancel this resource request. -class CancelResourceThrottle : public content::ResourceThrottle { +void SetOnlyAllowLoadFromCache( + net::URLRequest* request) { + int load_flags = request->load_flags(); + load_flags &= ~(net::LOAD_BYPASS_CACHE & + net::LOAD_VALIDATE_CACHE & + net::LOAD_PREFERRING_CACHE); + load_flags |= net::LOAD_ONLY_FROM_CACHE; + request->set_load_flags(load_flags); +} + +// May cancel this resource request based on result of Java callbacks. +class MaybeCancelResourceThrottle : public content::ResourceThrottle { public: + MaybeCancelResourceThrottle(int child_id, + int route_id, + net::URLRequest* request) + : child_id_(child_id), + route_id_(route_id), + request_(request) { } virtual void WillStartRequest(bool* defer) OVERRIDE; + + scoped_ptr<AwContentsIoThreadClient> GetIoThreadClient() { + return AwContentsIoThreadClient::FromID(child_id_, route_id_); + } + + private: + int child_id_; + int route_id_; + net::URLRequest* request_; }; -void CancelResourceThrottle::WillStartRequest(bool* defer) { - controller()->CancelWithError(net::ERR_ACCESS_DENIED); +void MaybeCancelResourceThrottle::WillStartRequest(bool* defer) { + // If there is no IO thread client set at this point, use a + // restrictive policy. This can happen for blocked popup + // windows for example. + // TODO(benm): Revert this to a DCHECK when the we support + // pop up windows being created in the WebView, as at that + // time we should always have an IoThreadClient at this + // point (i.e., the one associated with the new popup). + if (!GetIoThreadClient()) { + controller()->CancelWithError(net::ERR_ACCESS_DENIED); + return; + } + + // Part of implementation of WebSettings.allowContentAccess. + if (request_->url().SchemeIs(android_webview::kContentScheme) && + GetIoThreadClient()->ShouldBlockContentUrls()) { + controller()->CancelWithError(net::ERR_ACCESS_DENIED); + return; + } + + // Part of implementation of WebSettings.allowFileAccess. + if (request_->url().SchemeIsFile() && + GetIoThreadClient()->ShouldBlockFileUrls()) { + const GURL& url = request_->url(); + if (!url.has_path() || + // Application's assets and resources are always available. + (url.path().find(android_webview::kAndroidResourcePath) != 0 && + url.path().find(android_webview::kAndroidAssetPath) != 0)) { + controller()->CancelWithError(net::ERR_ACCESS_DENIED); + return; + } + } + + if (GetIoThreadClient()->ShouldBlockNetworkLoads()) { + if (request_->url().SchemeIs(chrome::kFtpScheme)) { + controller()->CancelWithError(net::ERR_ACCESS_DENIED); + return; + } + SetOnlyAllowLoadFromCache(request_); + } } } // namespace @@ -62,37 +127,8 @@ void AwResourceDispatcherHostDelegate::RequestBeginning( bool is_continuation_of_transferred_request, ScopedVector<content::ResourceThrottle>* throttles) { - scoped_ptr<AwContentsIoThreadClient> io_client = - AwContentsIoThreadClient::FromID(child_id, route_id); - DCHECK(io_client.get()); - - // Part of implementation of WebSettings.allowContentAccess. - if (request->url().SchemeIs(android_webview::kContentScheme) && - io_client->ShouldBlockContentUrls()) { - throttles->push_back(new CancelResourceThrottle); - } - - // Part of implementation of WebSettings.allowFileAccess. - if (request->url().SchemeIsFile() && io_client->ShouldBlockFileUrls()) { - const GURL& url = request->url(); - if (!url.has_path() || - // Application's assets and resources are always available. - (url.path().find(android_webview::kAndroidResourcePath) != 0 && - url.path().find(android_webview::kAndroidAssetPath) != 0)) { - throttles->push_back(new CancelResourceThrottle); - } - } - - // Part of implementation of WebSettings.blockNetworkLoads. - if (io_client->ShouldBlockNetworkLoads()) { - // Need to cancel ftp since it does not support net::LOAD_ONLY_FROM_CACHE - // flag, so must cancel the request if network load is blocked. - if (request->url().SchemeIs(chrome::kFtpScheme)) { - throttles->push_back(new CancelResourceThrottle); - } else { - SetOnlyAllowLoadFromCache(request); - } - } + throttles->push_back(new MaybeCancelResourceThrottle( + child_id, route_id, request)); // We ignore POST requests because of BUG=155250. if (resource_type == ResourceType::MAIN_FRAME && @@ -124,14 +160,4 @@ bool AwResourceDispatcherHostDelegate::HandleExternalProtocol(const GURL& url, return false; } -void AwResourceDispatcherHostDelegate::SetOnlyAllowLoadFromCache( - net::URLRequest* request) { - int load_flags = request->load_flags(); - load_flags &= ~(net::LOAD_BYPASS_CACHE & - net::LOAD_VALIDATE_CACHE & - net::LOAD_PREFERRING_CACHE); - load_flags |= net::LOAD_ONLY_FROM_CACHE; - request->set_load_flags(load_flags); -} - } diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h index 68d2352..bc7088c 100644 --- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h +++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h @@ -47,7 +47,6 @@ class AwResourceDispatcherHostDelegate AwResourceDispatcherHostDelegate>; AwResourceDispatcherHostDelegate(); virtual ~AwResourceDispatcherHostDelegate(); - void SetOnlyAllowLoadFromCache(net::URLRequest* request); DISALLOW_COPY_AND_ASSIGN(AwResourceDispatcherHostDelegate); }; diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java index 6ba07af..03dab29 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java @@ -136,6 +136,12 @@ public abstract class AwContentsClient extends ContentViewClient { Message resend = mHandler.obtainMessage(CONTINUE_PENDING_RELOAD, contentViewCore); AwContentsClient.this.onFormResubmission(dontResend, resend); } + + @Override + public boolean addNewContents(boolean isDialog, boolean isUserGesture) { + return AwContentsClient.this.onCreateWindow(isDialog, isUserGesture); + } + } class AwWebContentsObserver extends WebContentsObserverAndroid { @@ -215,6 +221,8 @@ public abstract class AwContentsClient extends ContentViewClient { protected abstract void handleJsPrompt(String url, String message, String defaultValue, JsPromptResultReceiver receiver); + protected abstract boolean onCreateWindow(boolean isDialog, boolean isUserGesture); + //-------------------------------------------------------------------------------------------- // Other WebView-specific methods //-------------------------------------------------------------------------------------------- diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java index 8cb1bff..46837e3 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java @@ -4,6 +4,7 @@ package org.chromium.android_webview; +import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; import org.chromium.content.components.web_contents_delegate_android.WebContentsDelegateAndroid; @@ -15,4 +16,8 @@ import org.chromium.content.components.web_contents_delegate_android.WebContents */ @JNINamespace("android_webview") public class AwWebContentsDelegate extends WebContentsDelegateAndroid { + @CalledByNative + public boolean addNewContents(boolean isDialog, boolean isUserGesture) { + return false; + } } diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java index 594b322..9245f7f 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java @@ -90,4 +90,9 @@ class NullContentsClient extends AwContentsClient { public void onFormResubmission(Message dontResend, Message resend) { dontResend.sendToTarget(); } + + @Override + public boolean onCreateWindow(boolean isDialog, boolean isUserGesture) { + return false; + } } diff --git a/android_webview/native/android_webview_jni_registrar.cc b/android_webview/native/android_webview_jni_registrar.cc index e223ecd..8926053 100644 --- a/android_webview/native/android_webview_jni_registrar.cc +++ b/android_webview/native/android_webview_jni_registrar.cc @@ -10,6 +10,7 @@ #include "android_webview/native/aw_contents_io_thread_client_impl.h" #include "android_webview/native/aw_http_auth_handler.h" #include "android_webview/native/aw_resource.h" +#include "android_webview/native/aw_web_contents_delegate.h" #include "android_webview/native/cookie_manager.h" #include "android_webview/native/intercepted_request_data_impl.h" #include "android_webview/native/js_result_handler.h" @@ -33,6 +34,7 @@ static base::android::RegistrationMethod kWebViewRegisteredMethods[] = { { "AwContentsIoThreadClientImpl", RegisterAwContentsIoThreadClientImpl}, { "AwHttpAuthHandler", RegisterAwHttpAuthHandler }, { "AwResource", AwResource::RegisterAwResource }, + { "AwWebContentsDelegate", RegisterAwWebContentsDelegate }, { "CookieManager", RegisterCookieManager }, { "InterceptedRequestDataImpl", RegisterInterceptedRequestData }, { "JsResultHandler", RegisterJsResultHandler }, diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc index 33e8edd..7610612 100644 --- a/android_webview/native/aw_web_contents_delegate.cc +++ b/android_webview/native/aw_web_contents_delegate.cc @@ -10,8 +10,10 @@ #include "android_webview/native/aw_javascript_dialog_creator.h" #include "content/public/browser/android/download_controller_android.h" #include "content/public/browser/web_contents.h" +#include "jni/AwWebContentsDelegate_jni.h" #include "net/http/http_request_headers.h" +using base::android::AttachCurrentThread; using content::WebContents; namespace android_webview { @@ -64,4 +66,35 @@ void AwWebContentsDelegate::OnStartDownload(WebContents* source, NOTREACHED(); // We always return false in CanDownload. } +void AwWebContentsDelegate::AddNewContents(content::WebContents* source, + content::WebContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture, + bool* was_blocked) { + JNIEnv* env = AttachCurrentThread(); + + bool is_dialog = disposition == NEW_POPUP; + bool create_popup = Java_AwWebContentsDelegate_addNewContents(env, + GetJavaDelegate(env).obj(), is_dialog, user_gesture); + + if (create_popup) { + // TODO(benm): Implement, taking ownership of new_contents. + NOTIMPLEMENTED() << "Popup windows are currently not supported for " + << "the chromium powered Android WebView."; + } else { + // The embedder has forgone their chance to display this popup + // window, so we're done with the WebContents now. + delete new_contents; + } + + if (was_blocked) { + *was_blocked = !create_popup; + } +} + +bool RegisterAwWebContentsDelegate(JNIEnv* env) { + return RegisterNativesImpl(env); +} + } // namespace android_webview diff --git a/android_webview/native/aw_web_contents_delegate.h b/android_webview/native/aw_web_contents_delegate.h index 2a2e902..7886ad8 100644 --- a/android_webview/native/aw_web_contents_delegate.h +++ b/android_webview/native/aw_web_contents_delegate.h @@ -32,8 +32,16 @@ class AwWebContentsDelegate const std::string& request_method) OVERRIDE; virtual void OnStartDownload(content::WebContents* source, content::DownloadItem* download) OVERRIDE; + virtual void AddNewContents(content::WebContents* source, + content::WebContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture, + bool* was_blocked) OVERRIDE; }; +bool RegisterAwWebContentsDelegate(JNIEnv* env); + } // namespace android_webview #endif // ANDROID_WEBVIEW_NATIVE_AW_WEB_CONTENTS_DELEGATE_H_ diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp index 65e7ff9..3bdc34b 100644 --- a/android_webview/native/webview_native.gyp +++ b/android_webview/native/webview_native.gyp @@ -68,6 +68,7 @@ '../java/src/org/chromium/android_webview/AwContentsIoThreadClient.java', '../java/src/org/chromium/android_webview/AwHttpAuthHandler.java', '../java/src/org/chromium/android_webview/AwResource.java', + '../java/src/org/chromium/android_webview/AwWebContentsDelegate.java', '../java/src/org/chromium/android_webview/CookieManager.java', '../java/src/org/chromium/android_webview/InterceptedRequestData.java', '../java/src/org/chromium/android_webview/JsResultHandler.java', |