Commit 94c2a565 authored by Evan Stade's avatar Evan Stade Committed by Commit Bot

WebLayer: add ErrorPageCallback

This allows the client to handle backing out of an error page, such as
an SSL interstitial, when there's no navigation entry to return to.
This would cover the case where the first page that a tab navigates to
has an SSL error.

The implementation for the Android shell simulates the user pressing
'back'.

Bug: 1022607
Change-Id: Id05e035d75b124b63c09c074b38a78eb1810e8e6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1910869Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarColin Blundell <blundell@chromium.org>
Commit-Queue: Evan Stade <estade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#715287}
parent 9c28ee38
......@@ -170,6 +170,7 @@ jumbo_static_library("weblayer_lib") {
"common/weblayer_paths.cc",
"common/weblayer_paths.h",
"public/download_delegate.h",
"public/error_page_delegate.h",
"public/fullscreen_delegate.h",
"public/main.h",
"public/navigation.h",
......@@ -320,6 +321,8 @@ jumbo_static_library("weblayer_lib") {
"browser/content_view_render_view.h",
"browser/download_callback_proxy.cc",
"browser/download_callback_proxy.h",
"browser/error_page_callback_proxy.cc",
"browser/error_page_callback_proxy.h",
"browser/fullscreen_callback_proxy.cc",
"browser/fullscreen_callback_proxy.h",
"browser/new_tab_callback_proxy.cc",
......
......@@ -20,7 +20,7 @@ instrumentation_test_apk("weblayer_instrumentation_test_apk") {
java_files = [
"src/org/chromium/weblayer/test/DataClearingTest.java",
"src/org/chromium/weblayer/test/DownloadCallbackTest.java",
"src/org/chromium/weblayer/test/EventUtils.java",
"src/org/chromium/weblayer/test/ErrorPageCallbackTest.java",
"src/org/chromium/weblayer/test/EventUtils.java",
"src/org/chromium/weblayer/test/ExecuteScriptTest.java",
"src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java",
......
// Copyright 2019 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.weblayer.test;
import android.support.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.net.test.ServerCertificate;
import org.chromium.weblayer.ErrorPageCallback;
import org.chromium.weblayer.shell.InstrumentationActivity;
/**
* Tests that ErrorPageCallback works as expected for handling error page interactions.
*/
@RunWith(BaseJUnit4ClassRunner.class)
public class ErrorPageCallbackTest {
@Rule
public InstrumentationActivityTestRule mActivityTestRule =
new InstrumentationActivityTestRule();
private InstrumentationActivity mActivity;
private Callback mCallback;
private EmbeddedTestServer mServer;
private static class Callback extends ErrorPageCallback {
private final CallbackHelper mCallbackHelper = new CallbackHelper();
@Override
public boolean onBackToSafety() {
mCallbackHelper.notifyCalled();
return true;
}
public void waitForBackToSafety() {
try {
mCallbackHelper.waitForFirst();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Before
public void setUp() {
mActivity = mActivityTestRule.launchShellWithUrl(null);
Assert.assertNotNull(mActivity);
mServer = EmbeddedTestServer.createAndStartHTTPSServer(
mActivity, ServerCertificate.CERT_MISMATCHED_NAME);
mCallback = new Callback();
TestThreadUtils.runOnUiThreadBlocking(
() -> { mActivity.getTab().setErrorPageCallback(mCallback); });
}
/**
* Verifies that ErrorPageCallback.onBackToSafety() is called after a user encounters an SSL
* error and clicks "back to safety".
*/
@Test
@SmallTest
public void testBackToSafetyOverride() throws Throwable {
mActivityTestRule.navigateAndWaitForFailure(
mServer.getURL("/weblayer/test/data/simple_page.html"));
mActivityTestRule.executeScriptSync(
"window.certificateErrorPageController.dontProceed();", false);
mCallback.waitForBackToSafety();
// TODO(estade): verify default behavior happens or is skipped as appropriate.
}
}
......@@ -47,7 +47,10 @@ public class InstrumentationActivityTestRule extends ActivityTestRule<Instrument
private static final class NavigationWaiter {
private String mUrl;
private Tab mTab;
private boolean mNavigationComplete;
private boolean mNavigationObserved;
/* True indicates that the expected navigation event is a failure. False indicates that the
* expected event is completion. */
private boolean mExpectFailure;
private boolean mDoneLoading;
private boolean mContentfulPaint;
private CallbackHelper mCallbackHelper = new CallbackHelper();
......@@ -55,8 +58,16 @@ public class InstrumentationActivityTestRule extends ActivityTestRule<Instrument
private NavigationCallback mNavigationCallback = new NavigationCallback() {
@Override
public void onNavigationCompleted(Navigation navigation) {
if (navigation.getUri().toString().equals(mUrl)) {
mNavigationComplete = true;
if (navigation.getUri().toString().equals(mUrl) && !mExpectFailure) {
mNavigationObserved = true;
checkComplete();
}
}
@Override
public void onNavigationFailed(Navigation navigation) {
if (navigation.getUri().toString().equals(mUrl) && mExpectFailure) {
mNavigationObserved = true;
checkComplete();
}
}
......@@ -76,10 +87,12 @@ public class InstrumentationActivityTestRule extends ActivityTestRule<Instrument
// |waitForPaint| should generally be set to true, unless there is a specific reason for
// onFirstContentfulPaint to not fire.
public NavigationWaiter(String url, Tab controller, boolean waitForPaint) {
public NavigationWaiter(
String url, Tab controller, boolean expectFailure, boolean waitForPaint) {
mUrl = url;
mTab = controller;
if (!waitForPaint) mContentfulPaint = true;
mExpectFailure = expectFailure;
}
public void navigateAndWait() {
......@@ -99,7 +112,7 @@ public class InstrumentationActivityTestRule extends ActivityTestRule<Instrument
}
private void checkComplete() {
if (mNavigationComplete && mDoneLoading && mContentfulPaint) {
if (mNavigationObserved && mDoneLoading && mContentfulPaint) {
mCallbackHelper.notifyCalled();
}
}
......@@ -179,8 +192,17 @@ public class InstrumentationActivityTestRule extends ActivityTestRule<Instrument
}
public void navigateAndWait(Tab controller, String url, boolean waitForPaint) {
NavigationWaiter waiter = new NavigationWaiter(url, controller, waitForPaint);
waiter.navigateAndWait();
(new NavigationWaiter(url, controller, false /* expectFailure */, waitForPaint))
.navigateAndWait();
}
/**
* Loads the given URL in the shell, expecting failure.
*/
public void navigateAndWaitForFailure(String url) {
(new NavigationWaiter(
url, getActivity().getTab(), true /* expectFailure */, true /* waitForPaint */))
.navigateAndWait();
}
/**
......
// Copyright 2019 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 "weblayer/browser/error_page_callback_proxy.h"
#include "url/gurl.h"
#include "weblayer/browser/java/jni/ErrorPageCallbackProxy_jni.h"
#include "weblayer/public/tab.h"
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
namespace weblayer {
ErrorPageCallbackProxy::ErrorPageCallbackProxy(JNIEnv* env,
jobject obj,
Tab* tab)
: tab_(tab), java_impl_(env, obj) {
tab_->SetErrorPageDelegate(this);
}
ErrorPageCallbackProxy::~ErrorPageCallbackProxy() {
tab_->SetErrorPageDelegate(nullptr);
}
bool ErrorPageCallbackProxy::OnBackToSafety() {
JNIEnv* env = AttachCurrentThread();
return Java_ErrorPageCallbackProxy_onBackToSafety(env, java_impl_);
}
static jlong JNI_ErrorPageCallbackProxy_CreateErrorPageCallbackProxy(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& proxy,
jlong tab) {
return reinterpret_cast<jlong>(
new ErrorPageCallbackProxy(env, proxy, reinterpret_cast<Tab*>(tab)));
}
static void JNI_ErrorPageCallbackProxy_DeleteErrorPageCallbackProxy(
JNIEnv* env,
jlong proxy) {
delete reinterpret_cast<ErrorPageCallbackProxy*>(proxy);
}
} // namespace weblayer
// Copyright 2019 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 WEBLAYER_BROWSER_ERROR_PAGE_CALLBACK_PROXY_H_
#define WEBLAYER_BROWSER_ERROR_PAGE_CALLBACK_PROXY_H_
#include <jni.h>
#include "base/android/scoped_java_ref.h"
#include "base/macros.h"
#include "weblayer/public/error_page_delegate.h"
namespace weblayer {
class Tab;
// ErrorPageCallbackProxy forwards all ErrorPageDelegate functions to the Java
// side. There is one ErrorPageCallbackProxy per Tab.
class ErrorPageCallbackProxy : public ErrorPageDelegate {
public:
ErrorPageCallbackProxy(JNIEnv* env, jobject obj, Tab* tab);
~ErrorPageCallbackProxy() override;
// ErrorPageDelegate:
bool OnBackToSafety() override;
private:
Tab* tab_;
base::android::ScopedJavaGlobalRef<jobject> java_impl_;
DISALLOW_COPY_AND_ASSIGN(ErrorPageCallbackProxy);
};
} // namespace weblayer
#endif // WEBLAYER_BROWSER_ERROR_PAGE_CALLBACK_PROXY_H_
......@@ -32,6 +32,7 @@ android_library("java") {
"org/chromium/weblayer_private/ContentView.java",
"org/chromium/weblayer_private/ContentViewRenderView.java",
"org/chromium/weblayer_private/DownloadCallbackProxy.java",
"org/chromium/weblayer_private/ErrorPageCallbackProxy.java",
"org/chromium/weblayer_private/ActionModeCallback.java",
"org/chromium/weblayer_private/FullscreenCallbackProxy.java",
"org/chromium/weblayer_private/NavigationControllerImpl.java",
......@@ -80,6 +81,7 @@ generate_jni("jni") {
sources = [
"org/chromium/weblayer_private/ContentViewRenderView.java",
"org/chromium/weblayer_private/DownloadCallbackProxy.java",
"org/chromium/weblayer_private/ErrorPageCallbackProxy.java",
"org/chromium/weblayer_private/FullscreenCallbackProxy.java",
"org/chromium/weblayer_private/NavigationControllerImpl.java",
"org/chromium/weblayer_private/NavigationImpl.java",
......@@ -146,6 +148,7 @@ android_aidl("aidl") {
"org/chromium/weblayer_private/interfaces/IChildProcessService.aidl",
"org/chromium/weblayer_private/interfaces/IClientNavigation.aidl",
"org/chromium/weblayer_private/interfaces/IDownloadCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/IErrorPageCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/IFullscreenCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/INavigation.aidl",
"org/chromium/weblayer_private/interfaces/INavigationController.aidl",
......
// Copyright 2019 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.weblayer_private;
import android.os.RemoteException;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.weblayer_private.interfaces.IErrorPageCallbackClient;
/**
* Owns the c++ ErrorPageCallbackProxy class, which is responsible for forwarding all
* ErrorPageDelegate calls to this class, which in turn forwards to the
* ErrorPageCallbackClient.
*/
@JNINamespace("weblayer")
public final class ErrorPageCallbackProxy {
private long mNativeErrorPageCallbackProxy;
private IErrorPageCallbackClient mClient;
ErrorPageCallbackProxy(long tab, IErrorPageCallbackClient client) {
assert client != null;
mClient = client;
mNativeErrorPageCallbackProxy =
ErrorPageCallbackProxyJni.get().createErrorPageCallbackProxy(this, tab);
}
public void setClient(IErrorPageCallbackClient client) {
assert client != null;
mClient = client;
}
public void destroy() {
ErrorPageCallbackProxyJni.get().deleteErrorPageCallbackProxy(mNativeErrorPageCallbackProxy);
mNativeErrorPageCallbackProxy = 0;
}
@CalledByNative
private boolean onBackToSafety() throws RemoteException {
return mClient.onBackToSafety();
}
@NativeMethods
interface Natives {
long createErrorPageCallbackProxy(ErrorPageCallbackProxy proxy, long tab);
void deleteErrorPageCallbackProxy(long proxy);
}
}
......@@ -18,6 +18,7 @@ import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ViewAndroidDelegate;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.weblayer_private.interfaces.IDownloadCallbackClient;
import org.chromium.weblayer_private.interfaces.IErrorPageCallbackClient;
import org.chromium.weblayer_private.interfaces.IFullscreenCallbackClient;
import org.chromium.weblayer_private.interfaces.INavigationControllerClient;
import org.chromium.weblayer_private.interfaces.IObjectWrapper;
......@@ -38,6 +39,7 @@ public final class TabImpl extends ITab.Stub {
private TabCallbackProxy mTabCallbackProxy;
private NavigationControllerImpl mNavigationController;
private DownloadCallbackProxy mDownloadCallbackProxy;
private ErrorPageCallbackProxy mErrorPageCallbackProxy;
private FullscreenCallbackProxy mFullscreenCallbackProxy;
private ViewAndroidDelegate mViewAndroidDelegate;
// BrowserImpl this TabImpl is in. This is only null during creation.
......@@ -191,6 +193,20 @@ public final class TabImpl extends ITab.Stub {
}
}
@Override
public void setErrorPageCallbackClient(IErrorPageCallbackClient client) {
if (client != null) {
if (mErrorPageCallbackProxy == null) {
mErrorPageCallbackProxy = new ErrorPageCallbackProxy(mNativeTab, client);
} else {
mErrorPageCallbackProxy.setClient(client);
}
} else if (mErrorPageCallbackProxy != null) {
mErrorPageCallbackProxy.destroy();
mErrorPageCallbackProxy = null;
}
}
@Override
public void setFullscreenCallbackClient(IFullscreenCallbackClient client) {
if (client != null) {
......@@ -229,6 +245,10 @@ public final class TabImpl extends ITab.Stub {
mDownloadCallbackProxy.destroy();
mDownloadCallbackProxy = null;
}
if (mErrorPageCallbackProxy != null) {
mErrorPageCallbackProxy.destroy();
mErrorPageCallbackProxy = null;
}
if (mFullscreenCallbackProxy != null) {
mFullscreenCallbackProxy.destroy();
mFullscreenCallbackProxy = null;
......
// Copyright 2019 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.weblayer_private.interfaces;
/**
* Allows the client to override the default way of handling user interactions
* with error pages (such as SSL interstitials).
*/
interface IErrorPageCallbackClient {
boolean onBackToSafety() = 0;
}
......@@ -5,6 +5,7 @@
package org.chromium.weblayer_private.interfaces;
import org.chromium.weblayer_private.interfaces.IDownloadCallbackClient;
import org.chromium.weblayer_private.interfaces.IErrorPageCallbackClient;
import org.chromium.weblayer_private.interfaces.IFullscreenCallbackClient;
import org.chromium.weblayer_private.interfaces.INavigationController;
import org.chromium.weblayer_private.interfaces.INavigationControllerClient;
......@@ -18,14 +19,16 @@ interface ITab {
void setDownloadCallbackClient(IDownloadCallbackClient client) = 2;
void setFullscreenCallbackClient(in IFullscreenCallbackClient client) = 3;
void setErrorPageCallbackClient(IErrorPageCallbackClient client) = 3;
void executeScript(in String script, boolean useSeparateIsolate, in IObjectWrapper callback) = 4;
void setFullscreenCallbackClient(in IFullscreenCallbackClient client) = 4;
void setNewTabsEnabled(in boolean enabled) = 5;
void executeScript(in String script, boolean useSeparateIsolate, in IObjectWrapper callback) = 5;
void setNewTabsEnabled(in boolean enabled) = 6;
// Returns a unique identifier for this Tab. The id is *not* unique across
// restores. The id is intended for the client library to avoid creating duplicate client objects
// for the same ITab.
int getId() = 6;
int getId() = 7;
}
......@@ -4,13 +4,11 @@
#include "weblayer/browser/new_tab_callback_proxy.h"
#include "base/android/jni_string.h"
#include "url/gurl.h"
#include "weblayer/browser/java/jni/NewTabCallbackProxy_jni.h"
#include "weblayer/browser/tab_impl.h"
using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;
namespace weblayer {
......
......@@ -19,6 +19,8 @@
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_errors.h"
#include "weblayer/browser/tab_impl.h"
#include "weblayer/public/error_page_delegate.h"
namespace weblayer {
......@@ -41,7 +43,7 @@ class SSLErrorControllerClient
std::move(metrics_helper),
nullptr /*prefs*/,
"en_US",
GURL("chrome://newtab")),
GURL("about:blank") /*default_safe_page*/),
cert_error_(cert_error),
ssl_info_(ssl_info),
request_url_(request_url) {}
......@@ -49,6 +51,11 @@ class SSLErrorControllerClient
~SSLErrorControllerClient() override = default;
void GoBack() override {
ErrorPageDelegate* delegate =
TabImpl::FromWebContents(web_contents_)->error_page_delegate();
if (delegate && delegate->OnBackToSafety())
return;
SecurityInterstitialControllerClient::GoBackAfterNavigationCommitted();
}
......
......@@ -6,6 +6,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/optional.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/interstitial_utils.h"
......@@ -74,10 +75,14 @@ class SSLBrowserTest : public WebLayerBrowserTest {
// ssl_browsertest.cc's CheckAuthenticationBrokenState() function.
}
void InteractWithBlockingPage(bool proceed) {
void InteractWithBlockingPage(
bool proceed,
base::Optional<GURL> previous_url = base::nullopt) {
GURL expected_url =
proceed ? bad_ssl_url() : previous_url.value_or(ok_url());
TestNavigationObserver navigation_observer(
proceed ? bad_ssl_url() : ok_url(),
TestNavigationObserver::NavigationEvent::Completion, shell());
expected_url, TestNavigationObserver::NavigationEvent::Completion,
shell());
ExecuteScript(shell(),
"window.certificateErrorPageController." +
std::string(proceed ? "proceed" : "dontProceed") + "();",
......@@ -121,6 +126,15 @@ IN_PROC_BROWSER_TEST_F(SSLBrowserTest, TakeMeBack) {
NavigateToPageWithSslErrorExpectBlocked();
}
// Tests clicking "take me back" on the interstitial page when there's no
// navigation history. The user should be taken to a safe page (about:blank).
IN_PROC_BROWSER_TEST_F(SSLBrowserTest, TakeMeBackEmptyNavigationHistory) {
NavigateToPageWithSslErrorExpectBlocked();
// Click "Take me back".
InteractWithBlockingPage(false /*proceed*/, GURL("about:blank"));
}
// Tests clicking proceed link on the interstitial page. This is a PRE_ test
// because it also acts as setup for the test below which verifies the behavior
// across restarts.
......
......@@ -136,6 +136,10 @@ void TabImpl::SetDownloadDelegate(DownloadDelegate* delegate) {
download_delegate_ = delegate;
}
void TabImpl::SetErrorPageDelegate(ErrorPageDelegate* delegate) {
error_page_delegate_ = delegate;
}
void TabImpl::SetFullscreenDelegate(FullscreenDelegate* delegate) {
if (delegate == fullscreen_delegate_)
return;
......
......@@ -71,10 +71,12 @@ class TabImpl : public Tab,
#endif
DownloadDelegate* download_delegate() { return download_delegate_; }
ErrorPageDelegate* error_page_delegate() { return error_page_delegate_; }
FullscreenDelegate* fullscreen_delegate() { return fullscreen_delegate_; }
// Tab:
void SetDownloadDelegate(DownloadDelegate* delegate) override;
void SetErrorPageDelegate(ErrorPageDelegate* delegate) override;
void SetFullscreenDelegate(FullscreenDelegate* delegate) override;
void SetNewTabDelegate(NewTabDelegate* delegate) override;
void AddObserver(TabObserver* observer) override;
......@@ -132,6 +134,7 @@ class TabImpl : public Tab,
void OnExitFullscreen();
DownloadDelegate* download_delegate_ = nullptr;
ErrorPageDelegate* error_page_delegate_ = nullptr;
FullscreenDelegate* fullscreen_delegate_ = nullptr;
NewTabDelegate* new_tab_delegate_ = nullptr;
ProfileImpl* profile_;
......
// Copyright 2019 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 WEBLAYER_PUBLIC_ERROR_PAGE_DELEGATE_H_
#define WEBLAYER_PUBLIC_ERROR_PAGE_DELEGATE_H_
#include <memory>
namespace weblayer {
// An interface that allows handling of interactions with error pages (such as
// SSL interstitials). If this interface is not used, default actions will be
// taken.
class ErrorPageDelegate {
public:
// The user has pressed "back to safety" on a blocking page. A return value of
// true will cause WebLayer to skip the default action.
virtual bool OnBackToSafety() = 0;
protected:
virtual ~ErrorPageDelegate() = default;
};
} // namespace weblayer
#endif // WEBLAYER_PUBLIC_ERROR_PAGE_DELEGATE_H_
......@@ -27,6 +27,7 @@ android_library("java") {
"org/chromium/weblayer/Callback.java",
"org/chromium/weblayer/ChildProcessService.java",
"org/chromium/weblayer/DownloadCallback.java",
"org/chromium/weblayer/ErrorPageCallback.java",
"org/chromium/weblayer/FullscreenCallback.java",
"org/chromium/weblayer/ListenableFuture.java",
"org/chromium/weblayer/ListenableResult.java",
......
// Copyright 2019 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.weblayer;
/**
* An interface that allows clients to handle error page interactions.
*/
public abstract class ErrorPageCallback {
/**
* The user has attempted to back out of an error page, such as one warning of an SSL error.
*
* @return true if the action was overridden and WebLayer should skip default handling.
*/
public abstract boolean onBackToSafety();
}
......@@ -16,6 +16,7 @@ import org.json.JSONObject;
import org.chromium.weblayer_private.interfaces.APICallException;
import org.chromium.weblayer_private.interfaces.IDownloadCallbackClient;
import org.chromium.weblayer_private.interfaces.IErrorPageCallbackClient;
import org.chromium.weblayer_private.interfaces.IFullscreenCallbackClient;
import org.chromium.weblayer_private.interfaces.IObjectWrapper;
import org.chromium.weblayer_private.interfaces.ITab;
......@@ -44,6 +45,7 @@ public final class Tab {
private final ObserverList<TabCallback> mCallbacks;
private Browser mBrowser;
private DownloadCallbackClientImpl mDownloadCallbackClient;
private ErrorPageCallbackClientImpl mErrorPageCallbackClient;
private NewTabCallback mNewTabCallback;
// Id from the remote side.
private final int mId;
......@@ -114,6 +116,21 @@ public final class Tab {
}
}
public void setErrorPageCallback(@Nullable ErrorPageCallback callback) {
ThreadCheck.ensureOnUiThread();
try {
if (callback != null) {
mErrorPageCallbackClient = new ErrorPageCallbackClientImpl(callback);
mImpl.setErrorPageCallbackClient(mErrorPageCallbackClient);
} else {
mErrorPageCallbackClient = null;
mImpl.setErrorPageCallbackClient(null);
}
} catch (RemoteException e) {
throw new APICallException(e);
}
}
public void setFullscreenCallback(@Nullable FullscreenCallback callback) {
ThreadCheck.ensureOnUiThread();
try {
......@@ -260,6 +277,23 @@ public final class Tab {
}
}
private static final class ErrorPageCallbackClientImpl extends IErrorPageCallbackClient.Stub {
private final ErrorPageCallback mCallback;
ErrorPageCallbackClientImpl(ErrorPageCallback callback) {
mCallback = callback;
}
public ErrorPageCallback getCallback() {
return mCallback;
}
@Override
public boolean onBackToSafety() {
return mCallback.onBackToSafety();
}
}
private static final class FullscreenCallbackClientImpl extends IFullscreenCallbackClient.Stub {
private FullscreenCallback mCallback;
......
......@@ -23,6 +23,7 @@ class WebView;
namespace weblayer {
class DownloadDelegate;
class ErrorPageDelegate;
class FullscreenDelegate;
class NavigationController;
class NewTabDelegate;
......@@ -43,6 +44,10 @@ class Tab {
// Sets the DownloadDelegate. If none is set, downloads will be dropped.
virtual void SetDownloadDelegate(DownloadDelegate* delegate) = 0;
// Sets the ErrorPageDelegate. If none is set, a default action will be taken
// for any given interaction with an error page.
virtual void SetErrorPageDelegate(ErrorPageDelegate* delegate) = 0;
// Sets the FullscreenDelegate. Setting a non-null value implicitly enables
// fullscreen.
virtual void SetFullscreenDelegate(FullscreenDelegate* delegate) = 0;
......
......@@ -29,6 +29,7 @@ import android.widget.TextView.OnEditorActionListener;
import org.chromium.weblayer.Browser;
import org.chromium.weblayer.DownloadCallback;
import org.chromium.weblayer.ErrorPageCallback;
import org.chromium.weblayer.FullscreenCallback;
import org.chromium.weblayer.NavigationCallback;
import org.chromium.weblayer.NavigationController;
......@@ -168,7 +169,7 @@ public class WebLayerShellActivity extends FragmentActivity {
mTab = mBrowser.getActiveTab();
String startupUrl = getUrlFromIntent(getIntent());
if (TextUtils.isEmpty(startupUrl)) {
startupUrl = "http://google.com";
startupUrl = "https://google.com";
}
loadUrl(startupUrl);
mTab.registerTabCallback(new TabCallback() {
......@@ -199,6 +200,13 @@ public class WebLayerShellActivity extends FragmentActivity {
getSystemService(DownloadManager.class).enqueue(request);
}
});
mTab.setErrorPageCallback(new ErrorPageCallback() {
@Override
public boolean onBackToSafety() {
fragment.getActivity().onBackPressed();
return true;
}
});
}
private Fragment getOrCreateBrowserFragment(Bundle savedInstanceState) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment