diff options
author | tedchoc@chromium.org <tedchoc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-21 23:25:48 +0000 |
---|---|---|
committer | tedchoc@chromium.org <tedchoc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-21 23:25:48 +0000 |
commit | 20e45098a7c93838e4f71c4a50ee6d3055471056 (patch) | |
tree | 88b91808d8f925dfa10da0e98b58823194c236b0 | |
parent | c8b8587beba4f52037eaefcba5f9207269ee2be2 (diff) | |
download | chromium_src-20e45098a7c93838e4f71c4a50ee6d3055471056.zip chromium_src-20e45098a7c93838e4f71c4a50ee6d3055471056.tar.gz chromium_src-20e45098a7c93838e4f71c4a50ee6d3055471056.tar.bz2 |
Add support for testing interstitials from Android.
Provides a simple delegate for creating interstitials from java and
tests to see that showing and hiding them works correctly.
BUG=
Review URL: https://chromiumcodereview.appspot.com/11308131
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169156 0039d316-1c4b-4281-b951-d872f2087c98
14 files changed, 399 insertions, 13 deletions
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java b/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java index bdd081e..f65d228 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java @@ -7,10 +7,7 @@ package org.chromium.chrome.browser; import android.content.Context; import android.text.TextUtils; -import org.chromium.chrome.browser.ChromeWebContentsDelegateAndroid; -import org.chromium.chrome.browser.ContentViewUtil; import org.chromium.content.browser.ContentView; -import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.LoadUrlParams; import org.chromium.content.common.CleanupReference; import org.chromium.ui.gfx.NativeWindow; @@ -18,7 +15,6 @@ import org.chromium.ui.gfx.NativeWindow; import java.util.ArrayList; import java.util.List; - /** * The basic Java representation of a tab. Contains and manages a {@link ContentView}. */ @@ -45,9 +41,9 @@ public class TabBase { } /** - * @param context The Context the view is running in. - * @param nativeWebContents A native pointer to the WebContents this tab represents. - * @param window The NativeWindow should represent this tab. + * @param context The Context the view is running in. + * @param nativeWebContentsPtr A native pointer to the WebContents this tab represents. + * @param window The NativeWindow should represent this tab. */ public TabBase(Context context, int nativeWebContentsPtr, NativeWindow window) { mWindow = window; @@ -154,7 +150,8 @@ public class TabBase { } } - private class TabBaseChromeWebContentsDelegateAndroid extends ChromeWebContentsDelegateAndroid { + private class TabBaseChromeWebContentsDelegateAndroid + extends ChromeWebContentsDelegateAndroid { @Override public void onLoadProgressChanged(int progress) { for (int i = 0; i < mObservers.size(); ++i) { diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/test/AutofillTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/test/AutofillTest.java index b5ed4d8..e1833f9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/test/AutofillTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/test/AutofillTest.java @@ -51,7 +51,7 @@ public class AutofillTest extends ChromiumTestShellTestBase { @Override public void setUp() throws Exception { super.setUp(); - ChromiumTestShellActivity activity = launchChromiumTestShellWithUrl("about:blank"); + ChromiumTestShellActivity activity = launchChromiumTestShellWithBlankPage(); assertNotNull(activity); waitForActiveShellToBeDoneLoading(); diff --git a/chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java b/chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java index cab24fd..aabfc48 100644 --- a/chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java +++ b/chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java @@ -43,6 +43,13 @@ public class ChromiumTestShellTestBase extends } /** + * Starts the ChromiumTestShell activity and loads a blank page. + */ + protected ChromiumTestShellActivity launchChromiumTestShellWithBlankPage() { + return launchChromiumTestShellWithUrl("about:blank"); + } + + /** * Waits for the Active shell to finish loading. This times out after * WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT milliseconds and it shouldn't be used for long * loading pages. Instead it should be used more for test initialization. The proper way diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc index 44ea562..757f5bf 100644 --- a/content/browser/android/browser_jni_registrar.cc +++ b/content/browser/android/browser_jni_registrar.cc @@ -13,6 +13,7 @@ #include "content/browser/android/content_view_render_view.h" #include "content/browser/android/content_view_statics.h" #include "content/browser/android/download_controller_android_impl.h" +#include "content/browser/android/interstitial_page_delegate_android.h" #include "content/browser/android/load_url_params.h" #include "content/browser/android/sandboxed_process_launcher.h" #include "content/browser/android/surface_texture_peer_browser_impl.h" @@ -38,9 +39,12 @@ base::android::RegistrationMethod kContentRegisteredMethods[] = { { "ContentViewCore", content::RegisterContentViewCore }, { "DownloadControllerAndroidImpl", content::DownloadControllerAndroidImpl::RegisterDownloadController }, - { "RegisterImeAdapter", content::RegisterImeAdapter }, + { "InterstitialPageDelegateAndroid", + content::InterstitialPageDelegateAndroid + ::RegisterInterstitialPageDelegateAndroid }, { "JavaBoundObject", content::JavaBoundObject::RegisterJavaBoundObject }, { "LoadUrlParams", content::RegisterLoadUrlParams }, + { "RegisterImeAdapter", content::RegisterImeAdapter }, { "SandboxedProcessLauncher", content::RegisterSandboxedProcessLauncher }, { "TouchPoint", content::RegisterTouchPoint }, { "WebContentsObserverAndroid", content::RegisterWebContentsObserverAndroid }, diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 02e4c2b..3dee35f6 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc @@ -11,6 +11,7 @@ #include "base/json/json_writer.h" #include "base/logging.h" #include "base/utf_string_conversions.h" +#include "content/browser/android/interstitial_page_delegate_android.h" #include "content/browser/android/load_url_params.h" #include "content/browser/android/touch_point.h" #include "content/browser/renderer_host/java/java_bound_object.h" @@ -1071,6 +1072,22 @@ void ContentViewCoreImpl::SetSize(JNIEnv* env, view->SetSize(gfx::Size(width, height)); } +void ContentViewCoreImpl::ShowInterstitialPage( + JNIEnv* env, jobject obj, jstring jurl, jint delegate_ptr) { + GURL url(base::android::ConvertJavaStringToUTF8(env, jurl)); + InterstitialPageDelegateAndroid* delegate = + reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr); + InterstitialPage* interstitial = InterstitialPage::Create( + web_contents_, false, url, delegate); + delegate->set_interstitial_page(interstitial); + interstitial->Show(); +} + +jboolean ContentViewCoreImpl::IsShowingInterstitialPage(JNIEnv* env, + jobject obj) { + return web_contents_->ShowingInterstitialPage(); +} + void ContentViewCoreImpl::ScrollFocusedEditableNodeIntoView(JNIEnv* env, jobject obj) { RenderViewHost* host = web_contents_->GetRenderViewHost(); diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index 4078f38..2496acc 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h @@ -184,6 +184,12 @@ class ContentViewCoreImpl : public ContentViewCore, jobject jbitmap); void SetSize(JNIEnv* env, jobject obj, jint width, jint height); + void ShowInterstitialPage(JNIEnv* env, + jobject obj, + jstring jurl, + jint delegate); + jboolean IsShowingInterstitialPage(JNIEnv* env, jobject obj); + // -------------------------------------------------------------------------- // Public methods that call to Java via JNI // -------------------------------------------------------------------------- diff --git a/content/browser/android/interstitial_page_delegate_android.cc b/content/browser/android/interstitial_page_delegate_android.cc new file mode 100644 index 0000000..4ed4890 --- /dev/null +++ b/content/browser/android/interstitial_page_delegate_android.cc @@ -0,0 +1,94 @@ +// 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 "content/browser/android/interstitial_page_delegate_android.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/android/scoped_java_ref.h" +#include "content/public/browser/interstitial_page.h" +#include "jni/InterstitialPageDelegateAndroid_jni.h" + +using base::android::AttachCurrentThread; +using base::android::ScopedJavaLocalRef; + +namespace content { + +InterstitialPageDelegateAndroid::InterstitialPageDelegateAndroid( + JNIEnv* env, + jobject obj, + const std::string& html_content) + : weak_java_obj_(env, obj), + html_content_(html_content), + page_(NULL) { +} + +InterstitialPageDelegateAndroid::~InterstitialPageDelegateAndroid() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj = weak_java_obj_.get(env); + if (obj.obj()) + Java_InterstitialPageDelegateAndroid_onNativeDestroyed(env, obj.obj()); +} + +void InterstitialPageDelegateAndroid::Proceed(JNIEnv* env, jobject obj) { + if (page_) + page_->Proceed(); +} + +void InterstitialPageDelegateAndroid::DontProceed(JNIEnv* env, + jobject obj) { + if (page_) + page_->DontProceed(); +} + +std::string InterstitialPageDelegateAndroid::GetHTMLContents() { + return html_content_; +} + +void InterstitialPageDelegateAndroid::OnProceed() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj = weak_java_obj_.get(env); + if (obj.obj()) + Java_InterstitialPageDelegateAndroid_onProceed(env, obj.obj()); +} + +void InterstitialPageDelegateAndroid::OnDontProceed() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj = weak_java_obj_.get(env); + if (obj.obj()) + Java_InterstitialPageDelegateAndroid_onDontProceed(env, obj.obj()); +} + +void InterstitialPageDelegateAndroid::CommandReceived( + const std::string& command) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj = weak_java_obj_.get(env); + if (obj.obj()) { + std::string sanitized_command(command); + // The JSONified response has quotes, remove them. + if (sanitized_command.length() > 1 && sanitized_command[0] == '"') { + sanitized_command = sanitized_command.substr( + 1, sanitized_command.length() - 2); + } + + Java_InterstitialPageDelegateAndroid_commandReceived( + env, obj.obj(), + base::android::ConvertUTF8ToJavaString(env, sanitized_command).obj()); + } +} + +// static +bool InterstitialPageDelegateAndroid + ::RegisterInterstitialPageDelegateAndroid(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +static jint Init(JNIEnv* env, jobject obj, jstring html_content) { + InterstitialPageDelegateAndroid* delegate = + new InterstitialPageDelegateAndroid( + env, obj, base::android::ConvertJavaStringToUTF8(env, html_content)); + return reinterpret_cast<jint>(delegate); +} + +} // namespace content diff --git a/content/browser/android/interstitial_page_delegate_android.h b/content/browser/android/interstitial_page_delegate_android.h new file mode 100644 index 0000000..f1ce12c --- /dev/null +++ b/content/browser/android/interstitial_page_delegate_android.h @@ -0,0 +1,56 @@ +// 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. + +#ifndef CONTENT_BROWSER_ANDROID_INTERSTITIAL_PAGE_DELEGATE_ANDROID_H_ +#define CONTENT_BROWSER_ANDROID_INTERSTITIAL_PAGE_DELEGATE_ANDROID_H_ + +#include <jni.h> +#include <string> + +#include "base/android/jni_helper.h" +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "content/common/content_export.h" +#include "content/public/browser/interstitial_page_delegate.h" + +namespace content { + +class InterstitialPage; +class WebContents; + +// Native counterpart that allows interstitial pages to be constructed and +// managed from Java. +class InterstitialPageDelegateAndroid : public InterstitialPageDelegate { + public: + InterstitialPageDelegateAndroid(JNIEnv* env, + jobject obj, + const std::string& html_content); + virtual ~InterstitialPageDelegateAndroid(); + + void set_interstitial_page(InterstitialPage* page) { page_ = page; } + + // Methods called from Java. + void Proceed(JNIEnv* env, jobject obj); + void DontProceed(JNIEnv* env, jobject obj); + + // Implementation of InterstitialPageDelegate + virtual std::string GetHTMLContents() OVERRIDE; + virtual void OnProceed() OVERRIDE; + virtual void OnDontProceed() OVERRIDE; + virtual void CommandReceived(const std::string& command) OVERRIDE; + + static bool RegisterInterstitialPageDelegateAndroid(JNIEnv* env); + + private: + JavaObjectWeakGlobalRef weak_java_obj_; + + std::string html_content_; + InterstitialPage* page_; // Owns this. + + DISALLOW_COPY_AND_ASSIGN(InterstitialPageDelegateAndroid); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_ANDROID_INTERSTITIAL_PAGE_DELEGATE_ANDROID_H_ diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 7b45c0ba..ae92ead 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -222,6 +222,8 @@ 'browser/android/download_controller_android_impl.cc', 'browser/android/download_controller_android_impl.h', 'browser/android/devtools_auth.cc', + 'browser/android/interstitial_page_delegate_android.cc', + 'browser/android/interstitial_page_delegate_android.h', 'browser/android/load_url_params.cc', 'browser/android/load_url_params.h', 'browser/android/media_player_manager_android.cc', diff --git a/content/content_jni.gypi b/content/content_jni.gypi index 6ec0314..91425d6 100644 --- a/content/content_jni.gypi +++ b/content/content_jni.gypi @@ -21,6 +21,7 @@ 'public/android/java/src/org/chromium/content/browser/DeviceOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/ImeAdapter.java', + 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/SandboxedProcessLauncher.java', diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 95efbed..46fcad0 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java @@ -738,6 +738,27 @@ public class ContentViewCore implements MotionEventDelegate { return null; } + /** + * Shows an interstitial page driven by the passed in delegate. + * + * @param url The URL being blocked by the interstitial. + * @param delegate The delegate handling the interstitial. + * @VisibleForTesting + */ + public void showInterstitialPage( + String url, InterstitialPageDelegateAndroid delegate) { + if (mNativeContentViewCore == 0) return; + nativeShowInterstitialPage(mNativeContentViewCore, url, delegate.getNative()); + } + + /** + * @return Whether the page is currently showing an interstitial, such as a bad HTTPS page. + */ + public boolean isShowingInterstitialPage() { + return mNativeContentViewCore == 0 ? + false : nativeIsShowingInterstitialPage(mNativeContentViewCore); + } + @CalledByNative public int getWidth() { return mViewportWidth; @@ -2315,6 +2336,10 @@ public class ContentViewCore implements MotionEventDelegate { private native String nativeGetTitle(int nativeContentViewCoreImpl); + private native void nativeShowInterstitialPage( + int nativeContentViewCoreImpl, String url, int nativeInterstitialPageDelegateAndroid); + private native boolean nativeIsShowingInterstitialPage(int nativeContentViewCoreImpl); + private native boolean nativeIsIncognito(int nativeContentViewCoreImpl); // Returns true if the native side crashed so that java side can draw a sad tab. diff --git a/content/public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java b/content/public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java new file mode 100644 index 0000000..5ccb6ea --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java @@ -0,0 +1,79 @@ +// 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. + +package org.chromium.content.browser; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; + +/** + * Allows the specification and handling of Interstitial pages in java. + */ +@JNINamespace("content") +public class InterstitialPageDelegateAndroid { + + private int mNativePtr; + + /** + * Constructs an interstitial with the given HTML content. + * + * @param htmlContent The HTML content for the interstitial. + */ + public InterstitialPageDelegateAndroid(String htmlContent) { + mNativePtr = nativeInit(htmlContent); + } + + /** + * @return The pointer to the underlying native counterpart. + */ + public int getNative() { + return mNativePtr; + } + + /** + * Called when "proceed" is triggered on the interstitial. + */ + @CalledByNative + protected void onProceed() { + } + + /** + * Called when "dont' proceed" is triggered on the interstitial. + */ + @CalledByNative + protected void onDontProceed() { + } + + /** + * Called when a command has been received from the interstitial. + * + * @param command The command that was received. + */ + @CalledByNative + protected void commandReceived(String command) { + } + + @CalledByNative + private void onNativeDestroyed() { + mNativePtr = 0; + } + + /** + * Notifies the native interstitial to proceed. + */ + protected void proceed() { + if (mNativePtr != 0) nativeProceed(mNativePtr); + } + + /** + * Notifies the native interstitial to not proceed. + */ + protected void dontProceed() { + if (mNativePtr != 0) nativeDontProceed(mNativePtr); + } + + private native int nativeInit(String htmlContent); + private native void nativeProceed(int nativeInterstitialPageDelegateAndroid); + private native void nativeDontProceed(int nativeInterstitialPageDelegateAndroid); +} diff --git a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java new file mode 100644 index 0000000..177fa6e --- /dev/null +++ b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java @@ -0,0 +1,101 @@ +// 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. + +package org.chromium.content.browser; + +import android.test.suitebuilder.annotation.LargeTest; + +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.Feature; +import org.chromium.content.browser.test.util.Criteria; +import org.chromium.content.browser.test.util.CriteriaHelper; +import org.chromium.content.browser.test.util.TouchCommon; +import org.chromium.content.browser.test.util.UiUtils; +import org.chromium.content_shell.ContentShellActivity; +import org.chromium.content_shell.ContentShellTestBase; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; + +/** + * Tests for interstitial pages. + */ +public class InterstitialPageTest extends ContentShellTestBase { + + private static final String URL = + "data:text/html;utf-8,<html><head></head><body>test</body></html>"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + ContentShellActivity activity = launchContentShellWithUrl(URL); + assertNotNull(activity); + waitForActiveShellToBeDoneLoading(); + } + + private ContentViewCore getActiveContentViewCore() { + return getActivity().getActiveContentView().getContentViewCore(); + } + + private boolean waitForInterstitial(final boolean shouldBeShown) throws InterruptedException { + return CriteriaHelper.pollForCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + try { + return ThreadUtils.runOnUiThreadBlocking(new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + return shouldBeShown + == getActiveContentViewCore().isShowingInterstitialPage(); + } + }); + } catch (ExecutionException e) { + return false; + } + } + }); + } + + /** + * Tests that showing and hiding an interstitial works. + */ + @LargeTest + @Feature({"Navigation"}) + public void testCloseInterstitial() throws InterruptedException { + final String proceedCommand = "PROCEED"; + final String htmlContent = + "<html>" + + "<head>" + + "<script>" + + "function sendCommand(command) {" + + "window.domAutomationController.setAutomationId(1);" + + "window.domAutomationController.send(command);" + + "}" + + "</script>" + + "</head>" + + "<body style='background-color:#FF0000' " + + "onclick='sendCommand(\"" + proceedCommand + "\");'>" + + "<h1>This is a scary interstitial page</h1>" + + "</body>" + + "</html>"; + final InterstitialPageDelegateAndroid delegate = + new InterstitialPageDelegateAndroid(htmlContent) { + @Override + protected void commandReceived(String command) { + assertEquals(command, proceedCommand); + proceed(); + } + }; + UiUtils.runOnUiThread(getActivity(), new Runnable() { + @Override + public void run() { + getActiveContentViewCore().showInterstitialPage(URL, delegate); + } + }); + assertTrue("Interstitial never shown.", waitForInterstitial(true)); + TouchCommon touchCommon = new TouchCommon(this); + touchCommon.singleClickViewRelative(getActivity().getActiveContentView(), 10, 10); + assertTrue("Interstitial never hidden.", waitForInterstitial(false)); + } +} diff --git a/content/shell/shell_main_delegate.cc b/content/shell/shell_main_delegate.cc index a3336b3..0d9337d 100644 --- a/content/shell/shell_main_delegate.cc +++ b/content/shell/shell_main_delegate.cc @@ -85,9 +85,6 @@ ShellMainDelegate::ShellMainDelegate() { } ShellMainDelegate::~ShellMainDelegate() { -#if defined(OS_ANDROID) - NOTREACHED(); -#endif } bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { |