blob: 566fffe1e853e5dcea14425eff560e9dc9d78367 [file] [log] [blame]
// 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.ScopedSysTraceEvent;
import org.chromium.base.Callback;
import org.chromium.base.metrics.RecordHistogram;
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. This should be 1:1 with
* WebViewContentsClientAdapter.
*/
public class SupportLibWebViewContentsClientAdapter {
private static final String WEBVIEW_CLIENT_COMPAT_NAME = "androidx.webkit.WebViewClientCompat";
private static final String[] EMPTY_FEATURE_LIST = new String[0];
private static final String COMPAT_CLIENT_HISTOGRAM =
"Android.WebView.SupportLibrary.ClientIsCompat";
// If {@code null}, this indicates the WebViewClient is not a WebViewClientCompat. Otherwise,
// this is a Proxy for the WebViewClientCompat.
@Nullable
private WebViewClientBoundaryInterface mWebViewClient;
private String[] mWebViewClientSupportedFeatures;
public SupportLibWebViewContentsClientAdapter() {
mWebViewClientSupportedFeatures = EMPTY_FEATURE_LIST;
}
public void setWebViewClient(WebViewClient possiblyCompatClient) {
try (ScopedSysTraceEvent event = ScopedSysTraceEvent.scoped(
"SupportLibWebViewContentsClientAdapter.setWebViewClient")) {
mWebViewClient = convertCompatClient(possiblyCompatClient);
mWebViewClientSupportedFeatures = mWebViewClient == null
? EMPTY_FEATURE_LIST
: mWebViewClient.getSupportedFeatures();
// We ignore the case where the client is set to null, since this is often done by
// WebView's internal logic (such as during destroy()), and would otherwise skew data.
if (possiblyCompatClient != null) {
RecordHistogram.recordBooleanHistogram(
COMPAT_CLIENT_HISTOGRAM, mWebViewClient != null);
}
}
}
@Nullable
private WebViewClientBoundaryInterface convertCompatClient(WebViewClient possiblyCompatClient) {
if (!BoundaryInterfaceReflectionUtil.instanceOfInOwnClassLoader(
possiblyCompatClient, WEBVIEW_CLIENT_COMPAT_NAME)) {
return null;
}
InvocationHandler handler =
BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(possiblyCompatClient);
return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
WebViewClientBoundaryInterface.class, handler);
}
/**
* 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;
return BoundaryInterfaceReflectionUtil.containsFeature(
mWebViewClientSupportedFeatures, featureName);
}
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.RECEIVE_WEB_RESOURCE_ERROR);
WebResourceErrorBoundaryInterface supportLibError = new SupportLibWebResourceError(error);
InvocationHandler errorHandler =
BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(supportLibError);
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 supportLibResponse =
new SupportLibSafeBrowsingResponse(callback);
InvocationHandler responseHandler =
BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(supportLibResponse);
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);
}
}