Commit f3b8b74e authored by Nate Fischer's avatar Nate Fischer Committed by Commit Bot

AW: implement support lib callbacks

This implements support library callbacks (WebViewclientCompat). This
creates a new layer (support_library/callback) which the glue layer
depends on. This dependency lets us instantiate a
SupportLibWebViewContentsClientAdapter inside setWebViewClient(), and
benefit from the glue layer's parameter cleanup code (e.g., in
onReceivedError2()).

The support_library/callback glue must be a separate layer from
support_library/ glue, as that already depends on the webkit glue to
initiate state. Implementing callbacks as a separate target avoids the
circular dependency.

This refactors the (post-L) glue layer callback methods to take the
following precedence:

 1. SupportLibWebViewContentsClientAdapter (if it supports the callback)
 2. WebViewClient (if on the appropriate platform level)
 3. Default behavior (implementation provided by the glue layer)

This implements both category 1 and 2 APIs.

Design doc: http://go/wv-support-library-callbacks

Bug: 781764
Test: manual - built test application with latest support-lib changes
Change-Id: I21e28493873e670cfd428c7eeef12b0e212aeec4
Reviewed-on: https://chromium-review.googlesource.com/989015Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Reviewed-by: default avatarGustav Sennton <gsennton@chromium.org>
Commit-Queue: Nate Fischer <ntfschr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548538}
parent 58f68d3c
...@@ -9,6 +9,8 @@ glue_library_deps = [ ...@@ -9,6 +9,8 @@ glue_library_deps = [
"//android_webview:android_webview_commandline_java", "//android_webview:android_webview_commandline_java",
"//android_webview:android_webview_platform_services_java", "//android_webview:android_webview_platform_services_java",
"//android_webview:system_webview_manifest", "//android_webview:system_webview_manifest",
"//android_webview/support_library/boundary_interfaces:boundary_interface_java",
"//android_webview/support_library/callback:callback_java",
"//base:base_java", "//base:base_java",
"//components/autofill/android:autofill_java", "//components/autofill/android:autofill_java",
"//components/autofill/android:provider_java", "//components/autofill/android:provider_java",
......
...@@ -13,6 +13,19 @@ public class Features { ...@@ -13,6 +13,19 @@ public class Features {
// This class just contains constants representing features. // This class just contains constants representing features.
private Features() {} private Features() {}
// WebViewCompat.postVisualStateCallback // WebViewCompat#postVisualStateCallback
// WebViewClientCompat#onPageCommitVisible
public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK"; public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
// WebViewClientCompat#onReceivedError(WebView, WebResourceRequest, WebResourceError)
public static final String WEB_RESOURCE_ERROR = "WEB_RESOURCE_ERROR";
// WebViewClientCompat#onReceivedHttpError
public static final String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
// WebViewClientCompat#onSafeBrowsingHit
public static final String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
// WebViewClientCompat#shouldOverrideUrlLoading
public static final String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
} }
# Copyright 2018 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.
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
android_library("callback_java") {
java_files = [ "java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java" ]
deps = [
"//android_webview:android_webview_commandline_java",
"//android_webview:android_webview_java",
"//android_webview/support_library/boundary_interfaces:boundary_interface_java",
"//base:base_java",
]
}
// Copyright 2018 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.support_lib_callback_glue;
import android.support.annotation.Nullable;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import org.chromium.android_webview.AwContentsClient.AwWebResourceError;
import org.chromium.android_webview.AwSafeBrowsingResponse;
import org.chromium.android_webview.SafeBrowsingAction;
import org.chromium.base.Callback;
import org.chromium.support_lib_boundary.SafeBrowsingResponseBoundaryInterface;
import org.chromium.support_lib_boundary.WebResourceErrorBoundaryInterface;
import org.chromium.support_lib_boundary.WebViewClientBoundaryInterface;
import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
import org.chromium.support_lib_boundary.util.Features;
import java.lang.reflect.InvocationHandler;
/**
* Support library glue version of WebViewContentsClientAdapter.
*/
public class SupportLibWebViewContentsClientAdapter {
private static final String WEBVIEW_CLIENT_COMPAT_NAME = "androidx.webkit.WebViewClientCompat";
// If {@code null}, this indicates the WebViewClient is not a WebViewClientCompat. Otherwise,
// this is a Proxy for the WebViewClientCompat.
@Nullable
private WebViewClientBoundaryInterface mWebViewClient;
private static class SafeBrowsingResponseDelegate
implements SafeBrowsingResponseBoundaryInterface {
private Callback<AwSafeBrowsingResponse> mCallback;
SafeBrowsingResponseDelegate(Callback<AwSafeBrowsingResponse> callback) {
mCallback = callback;
}
@Override
public void showInterstitial(boolean allowReporting) {
mCallback.onResult(new AwSafeBrowsingResponse(
SafeBrowsingAction.SHOW_INTERSTITIAL, allowReporting));
}
@Override
public void proceed(boolean report) {
mCallback.onResult(new AwSafeBrowsingResponse(SafeBrowsingAction.PROCEED, report));
}
@Override
public void backToSafety(boolean report) {
mCallback.onResult(
new AwSafeBrowsingResponse(SafeBrowsingAction.BACK_TO_SAFETY, report));
}
};
private static class WebResourceErrorDelegate implements WebResourceErrorBoundaryInterface {
private AwWebResourceError mError;
WebResourceErrorDelegate(AwWebResourceError error) {
mError = error;
}
@Override
public int getErrorCode() {
return mError.errorCode;
}
@Override
public CharSequence getDescription() {
return mError.description;
}
};
public SupportLibWebViewContentsClientAdapter(WebViewClient possiblyCompatClient) {
mWebViewClient = convertCompatClient(possiblyCompatClient);
}
@Nullable
private WebViewClientBoundaryInterface convertCompatClient(WebViewClient possiblyCompatClient) {
if (!clientIsCompat(possiblyCompatClient)) return null;
InvocationHandler handler =
BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(possiblyCompatClient);
return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
WebViewClientBoundaryInterface.class, handler);
}
private boolean clientIsCompat(WebViewClient possiblyCompatClient) {
try {
Class compatClass = Class.forName(WEBVIEW_CLIENT_COMPAT_NAME, false,
possiblyCompatClient.getClass().getClassLoader());
return compatClass.isInstance(possiblyCompatClient);
} catch (ClassNotFoundException e) {
// If WEBVIEW_CLIENT_COMPAT_NAME is not in the ClassLoader, then this cannot be an
// instance of WebViewClientCompat.
return false;
}
}
/**
* Indicates whether this client can handle the callback(s) assocated with {@param featureName}.
* This should be called with the correct feature name before invoking the corresponding
* callback, and the callback must not be called if this returns {@code false} for the feature.
*
* @param featureName the feature for the desired callback.
* @return {@code true} if this client can handle the feature.
*/
public boolean isFeatureAvailable(String featureName) {
if (mWebViewClient == null) return false;
// TODO(ntfschr): provide a real implementation, which consults the WebViewClientCompat.
return true;
}
public void onPageCommitVisible(WebView webView, String url) {
assert isFeatureAvailable(Features.VISUAL_STATE_CALLBACK);
mWebViewClient.onPageCommitVisible(webView, url);
}
public void onReceivedError(
WebView webView, WebResourceRequest request, final AwWebResourceError error) {
assert isFeatureAvailable(Features.WEB_RESOURCE_ERROR);
WebResourceErrorBoundaryInterface errorDelegate = new WebResourceErrorDelegate(error);
InvocationHandler errorHandler =
BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(errorDelegate);
mWebViewClient.onReceivedError(webView, request, errorHandler);
}
public void onReceivedHttpError(
WebView webView, WebResourceRequest request, WebResourceResponse response) {
assert isFeatureAvailable(Features.RECEIVE_HTTP_ERROR);
mWebViewClient.onReceivedHttpError(webView, request, response);
}
public void onSafeBrowsingHit(WebView webView, WebResourceRequest request, int threatType,
Callback<AwSafeBrowsingResponse> callback) {
assert isFeatureAvailable(Features.SAFE_BROWSING_HIT);
SafeBrowsingResponseBoundaryInterface responseDelegate =
new SafeBrowsingResponseDelegate(callback);
InvocationHandler responseHandler =
BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(responseDelegate);
mWebViewClient.onSafeBrowsingHit(webView, request, threatType, responseHandler);
}
public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest request) {
assert isFeatureAvailable(Features.SHOULD_OVERRIDE_WITH_REDIRECTS);
return mWebViewClient.shouldOverrideUrlLoading(webView, request);
}
}
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